Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merging next to main for release 2.3.0 #33

Merged
merged 24 commits into from
Feb 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
repos:
- repo: https://github.com/phantomcyber/dev-cicd-tools
rev: v1.16
rev: v1.17
hooks:
- id: org-hook
- id: package-app-dependencies
args: ["-d", "./Dockerfile.wheels"]
- repo: https://github.com/Yelp/detect-secrets
rev: v1.4.0
hooks:
Expand Down
2 changes: 2 additions & 0 deletions Dockerfile.wheels
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
FROM quay.io/pypa/manylinux2014_x86_64
RUN yum install krb5-devel krb5-workstation -y
32 changes: 31 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
# Windows Remote Management

Publisher: Splunk
Connector Version: 2.2.9
Connector Version: 2.3.0
Product Vendor: Microsoft
Product Name: Windows Remote Management
Product Version Supported (regex): ".\*"
Expand Down Expand Up @@ -130,6 +130,33 @@ or some other command which you want to start but don't care for the output, the
**async** parameter. After the command starts, it will return a **command_id** and **shell_id** ,
which you can optionally use to retrieve the output of that command at a later time.

### Certificate Authentication

To authenticate using SSL certificates, select `certificate` authentication in asset configuration method and pass following configuration parameters.

* cert_pem_path - A path to signed certificate file that is trusted by the Windows instance, in PEM format

* cert_key_pem_path - A filepath to key used to generate cert_pem file

* ca_trust_path - The certificate of the certificate authority that signed cert_file. It's needed only when you set up your own certificate authority.

It is recommended that these files be placed under the <PHANTOM_HOME>/etc/ssl/ directory. These files must be readable by the phantom-worker user.

### Kerberos Authentication

To authenticate using Kerberos, select `kerberos` authentication in asset configuration and provide hostname and username used for authorization.
You'll also need to setup your instance to support Kerberos:

- Kerberos packages have to be installed:
- for Debian/Ubuntu/etc: `sudo apt-get install krb5-user`
- for RHEL/CentOS/etc: `sudo yum install krb5-workstation krb5-libs`

- `/etc/krb5.conf` needs to be properly configured for your realm and kdc
- If there is no DNS configuration, `hosts` file will need to have mappings for server with mssccm under same domain as on Windows server
- `kinit` must be run for principal that will be used to connect to msccm
- It should be noted that Kerberos tickets will expire, so it is recommended to use a script to
run `kinit` periodically to refresh the ticket for the user, alternatively `keytab` file can be created on server and used on client for connectivity.


### Configuration Variables
The below configuration variables are required for this Connector to operate. These variables are specified when configuring a Windows Remote Management asset in SOAR.
Expand All @@ -144,6 +171,9 @@ VARIABLE | REQUIRED | TYPE | DESCRIPTION
**username** | required | string | Username
**password** | required | password | Password
**transport** | required | string | Type of transport to use
**cert_pem_path** | optional | string | Path to SSL certificate PEM file
**cert_key_pem_path** | optional | string | Path to SSL key file
**ca_trust_path** | optional | string | Path to trusted CRT file

### Supported Actions
[test connectivity](#action-test-connectivity) - Validate the asset configuration for connectivity using supplied configuration
Expand Down
27 changes: 27 additions & 0 deletions manual_readme_content.md
Original file line number Diff line number Diff line change
Expand Up @@ -117,3 +117,30 @@ default, the app will wait for these actions to finish. In the case of starting
or some other command which you want to start but don't care for the output, then you can check the
**async** parameter. After the command starts, it will return a **command_id** and **shell_id** ,
which you can optionally use to retrieve the output of that command at a later time.

### Certificate Authentication

To authenticate using SSL certificates, select `certificate` authentication in asset configuration method and pass following configuration parameters.

* cert_pem_path - A path to signed certificate file that is trusted by the Windows instance, in PEM format

* cert_key_pem_path - A filepath to key used to generate cert_pem file

* ca_trust_path - The certificate of the certificate authority that signed cert_file. It's needed only when you set up your own certificate authority.

It is recommended that these files be placed under the <PHANTOM_HOME>/etc/ssl/ directory. These files must be readable by the phantom-worker user.

### Kerberos Authentication

To authenticate using Kerberos, select `kerberos` authentication in asset configuration and provide hostname and username used for authorization.
You'll also need to setup your instance to support Kerberos:

- Kerberos packages have to be installed:
- for Debian/Ubuntu/etc: `sudo apt-get install krb5-user`
- for RHEL/CentOS/etc: `sudo yum install krb5-workstation krb5-libs`

- `/etc/krb5.conf` needs to be properly configured for your realm and kdc
- If there is no DNS configuration, `hosts` file will need to have mappings for server with mssccm under same domain as on Windows server
- `kinit` must be run for principal that will be used to connect to msccm
- It should be noted that Kerberos tickets will expire, so it is recommended to use a script to
run `kinit` periodically to refresh the ticket for the user, alternatively `keytab` file can be created on server and used on client for connectivity.
2 changes: 2 additions & 0 deletions release_notes/2.3.0.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
* [PAPP-32933] Kerberos and Certificate authentication support.
* User can now select Certificate and Kerberos as transport methods
1 change: 1 addition & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
beautifulsoup4==4.9.1
pykerberos==1.2.4
pywinrm==0.4.3
# Pinned to the current platform version
requests==2.31.0
Expand Down
Binary file not shown.
Binary file added wheels/py3/soupsieve-2.3.2.post1-py3-none-any.whl
Binary file not shown.
Binary file added wheels/py3/urllib3-2.2.1-py3-none-any.whl
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
102 changes: 97 additions & 5 deletions winrm.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@
"product_version_regex": ".*",
"publisher": "Splunk",
"license": "Copyright (c) 2018-2024 Splunk Inc.",
"app_version": "2.2.9",
"utctime_updated": "2024-02-16T10:23:24.000000Z",
"app_version": "2.3.0",
"utctime_updated": "2024-02-28T09:53:35.000000Z",
"package_name": "phantom_winrm",
"main_module": "winrm_connector.py",
"min_phantom_version": "6.1.1",
Expand Down Expand Up @@ -72,10 +72,30 @@
"required": true,
"value_list": [
"basic",
"ntlm"
"ntlm",
"certificate",
"kerberos"
],
"default": "basic",
"order": 7
},
"cert_pem_path": {
"description": "Path to SSL certificate PEM file",
"data_type": "string",
"required": false,
"order": 8
},
"cert_key_pem_path": {
"description": "Path to SSL key file",
"data_type": "string",
"required": false,
"order": 9
},
"ca_trust_path": {
"description": "Path to trusted CRT file",
"data_type": "string",
"required": false,
"order": 10
}
},
"actions": [
Expand Down Expand Up @@ -3321,7 +3341,7 @@
},
{
"module": "cryptography",
"input_file": "wheels/py39/cryptography-42.0.2-cp39-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl"
"input_file": "wheels/py39/cryptography-42.0.4-cp39-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl"
},
{
"module": "idna",
Expand All @@ -3331,6 +3351,10 @@
"module": "pycparser",
"input_file": "wheels/shared/pycparser-2.21-py2.py3-none-any.whl"
},
{
"module": "pykerberos",
"input_file": "wheels/py39/pykerberos-1.2.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"
},
{
"module": "pyspnego",
"input_file": "wheels/py3/pyspnego-0.10.2-py3-none-any.whl"
Expand All @@ -3355,6 +3379,74 @@
"module": "soupsieve",
"input_file": "wheels/py3/soupsieve-2.5-py3-none-any.whl"
},
{
"module": "urllib3",
"input_file": "wheels/py3/urllib3-2.2.1-py3-none-any.whl"
},
{
"module": "xmltodict",
"input_file": "wheels/shared/xmltodict-0.13.0-py2.py3-none-any.whl"
}
]
},
"pip_dependencies": {
"wheel": [
{
"module": "beautifulsoup4",
"input_file": "wheels/py3/beautifulsoup4-4.9.1-py3-none-any.whl"
},
{
"module": "certifi",
"input_file": "wheels/py3/certifi-2024.2.2-py3-none-any.whl"
},
{
"module": "cffi",
"input_file": "wheels/py36/cffi-1.15.1-cp36-cp36m-manylinux1_x86_64.manylinux_2_5_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl"
},
{
"module": "charset_normalizer",
"input_file": "wheels/py3/charset_normalizer-2.0.12-py3-none-any.whl"
},
{
"module": "cryptography",
"input_file": "wheels/py36/cryptography-40.0.2-cp36-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl"
},
{
"module": "idna",
"input_file": "wheels/py3/idna-3.6-py3-none-any.whl"
},
{
"module": "ntlm_auth",
"input_file": "wheels/shared/ntlm_auth-1.5.0-py2.py3-none-any.whl"
},
{
"module": "pycparser",
"input_file": "wheels/shared/pycparser-2.21-py2.py3-none-any.whl"
},
{
"module": "pykerberos",
"input_file": "wheels/py36/pykerberos-1.2.4-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"
},
{
"module": "pywinrm",
"input_file": "wheels/shared/pywinrm-0.4.3-py2.py3-none-any.whl"
},
{
"module": "requests",
"input_file": "wheels/shared/requests-2.27.1-py2.py3-none-any.whl"
},
{
"module": "requests_ntlm",
"input_file": "wheels/shared/requests_ntlm-1.1.0-py2.py3-none-any.whl"
},
{
"module": "six",
"input_file": "wheels/shared/six-1.16.0-py2.py3-none-any.whl"
},
{
"module": "soupsieve",
"input_file": "wheels/py3/soupsieve-2.3.2.post1-py3-none-any.whl"
},
{
"module": "urllib3",
"input_file": "wheels/shared/urllib3-1.26.18-py2.py3-none-any.whl"
Expand All @@ -3365,4 +3457,4 @@
}
]
}
}
}
46 changes: 33 additions & 13 deletions winrm_connector.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
from bs4 import UnicodeDammit
from phantom.action_result import ActionResult
from phantom.base_connector import BaseConnector
from phantom_common.install_info import is_fips_enabled

# Local imports
import parse_callbacks as pc
Expand Down Expand Up @@ -187,6 +188,11 @@ def _sanitize_string(self, string):
# break any double quotes which are found, then we break any $, which is used to declare variables
return string.replace('`', '``').replace('"', '`"').replace('$', '`$').replace('&', '`&').replace(')', '`)').replace('(', '`(')

def _get_fips_enabled(self):
fips_enabled = is_fips_enabled()
self.debug_print(f'FIPS is enabled: {fips_enabled}')
return fips_enabled

def _create_ps_script(self, action_result, args, whitelist_args=set(), cmd_prefix="", cmd_suffix=""):
# Here, you can pass it something like {"val1": "value"} which will generate a string for "-val1 value"
# "For your convenience" you can also pass it a list of strings and dicts, something like [val1, {"val2": "asdf"}, foo],
Expand Down Expand Up @@ -224,19 +230,19 @@ def _create_ps_script(self, action_result, args, whitelist_args=set(), cmd_prefi
def _init_session(self, action_result, param=None):
config = self.get_config()

default_protocol = config.get('default_protocol', 'http')
default_protocol = config.get(consts.WINRM_CONFIG_PROTOCOL, 'http')
ret_val, default_port = self._validate_integer(
action_result,
config.get('default_port', 5985 if default_protocol == 'http' else 5986),
config.get(consts.WINRM_CONFIG_PORT, 5985 if default_protocol == 'http' else 5986),
"Default port",
True)
if phantom.is_fail(ret_val):
return action_result.get_status()

endpoint = self._handle_py_ver_compat_for_input_str(config.get(consts.WINRM_CONFIG_ENDPOINT))
if param:
endpoint = self._handle_py_ver_compat_for_input_str(param.get('ip_hostname', config.get('endpoint')))
else:
endpoint = self._handle_py_ver_compat_for_input_str(config.get('endpoint'))
endpoint = self._handle_py_ver_compat_for_input_str(param.get('ip_hostname', endpoint))

if endpoint is None:
return action_result.set_status(
phantom.APP_ERROR, "No Endpoint Configured"
Expand All @@ -245,12 +251,16 @@ def _init_session(self, action_result, param=None):
endpoint = '{0}://{1}'.format(default_protocol, endpoint)
if re.search(r':\d+$', endpoint, re.UNICODE | re.IGNORECASE) is None:
endpoint = '{0}:{1}'.format(endpoint, default_port)
username = config['username']
password = config['password']
transport = config.get('transport')
domain = self._handle_py_ver_compat_for_input_str(config.get('domain'))
username = config[consts.WINRM_CONFIG_USERNAME]
password = config[consts.WINRM_CONFIG_PASSWORD]
transport = config.get(consts.WINRM_CONFIG_TRANSPORT)
domain = self._handle_py_ver_compat_for_input_str(config.get(consts.WINRM_CONFIG_DOMAIN))

verify_bool = config.get(phantom.APP_JSON_VERIFY, False)
cert_pem_path = None
cert_key_pem_path = None
cert_ca_trust_path = config.get(consts.WINRM_CONFIG_CA_TRUST, "legacy_requests")

if verify_bool:
verify = 'validate'
else:
Expand All @@ -262,12 +272,19 @@ def _init_session(self, action_result, param=None):
"Warning: Domain is set but transport type is set to 'basic'"
)
elif transport == 'ntlm':
if self._get_fips_enabled():
return action_result.set_status(
phantom.APP_ERROR, "This transport type is not supported when FIPS is enabled"
)
if domain:
username = r'{}\{}'.format(domain, username)
elif transport == 'kerberos':
return action_result.set_status(
phantom.APP_ERROR, "This transport type is not yet implemented"
)
if domain:
username = '{}@{}'.format(username, domain)
elif transport == 'certificate':
username = r'{}\{}'.format(domain, username)
cert_pem_path = config.get(consts.WINRM_CONFIG_CERT_PEM)
cert_key_pem_path = config.get(consts.WINRM_CONFIG_CERT_KEY_PEM)
elif transport == 'credssp':
return action_result.set_status(
phantom.APP_ERROR, "This transport type is not yet implemented"
Expand All @@ -281,7 +298,10 @@ def _init_session(self, action_result, param=None):
endpoint,
auth=(username, password),
server_cert_validation=verify,
transport=transport
transport=transport,
cert_pem=cert_pem_path,
cert_key_pem=cert_key_pem_path,
ca_trust_path=cert_ca_trust_path
)
self._protocol = self._session.protocol

Expand Down
13 changes: 13 additions & 0 deletions winrm_consts.py
Original file line number Diff line number Diff line change
Expand Up @@ -108,3 +108,16 @@
LOCATION_VALUE_LIST = ["local", "domain", "effective"]
DENY_ALLOW_VALUE_LIST = ["deny", "allow"]
VALUE_LIST_VALIDATION_MESSAGE = "Please provide valid input from {} in '{}' action parameter"

# Config keys

WINRM_CONFIG_ENDPOINT = "endpoint"
WINRM_CONFIG_PROTOCOL = "default_protocol"
WINRM_CONFIG_PORT = "default_port"
WINRM_CONFIG_USERNAME = "username"
WINRM_CONFIG_PASSWORD = "password"
WINRM_CONFIG_TRANSPORT = "transport"
WINRM_CONFIG_DOMAIN = "domain"
WINRM_CONFIG_CERT_PEM = "cert_pem_path"
WINRM_CONFIG_CERT_KEY_PEM = "cert_key_pem_path"
WINRM_CONFIG_CA_TRUST = "ca_trust_path"
Loading