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

Core get-prevalence #19543

Merged
merged 20 commits into from Jun 27, 2022
Merged
Show file tree
Hide file tree
Changes from 16 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
74 changes: 72 additions & 2 deletions Packs/Core/Integrations/CortexCoreIR/CortexCoreIR.py
Expand Up @@ -10,14 +10,22 @@
INTEGRATION_CONTEXT_BRAND = 'Core'
INTEGRATION_NAME = 'Cortex Core - IR'


XSOAR_RESOLVED_STATUS_TO_Core = {
'Other': 'resolved_other',
'Duplicate': 'resolved_duplicate',
'False Positive': 'resolved_false_positive',
'Resolved': 'resolved_true_positive',
}

PREVALENCE_COMMANDS = {
'core-get-hash-analytics-prevalence': 'hash',
'core-get-IP-analytics-prevalence': 'ip',
'core-get-domain-analytics-prevalence': 'domain',
'core-get-process-analytics-prevalence': 'process',
'core-get-registry-analytics-prevalence': 'registry',
'core-get-cmd-analytics-prevalence': 'cmd',
}


class Client(CoreClient):

Expand Down Expand Up @@ -49,6 +57,10 @@ def report_incorrect_wildfire(self, file_hash: str, new_verdict: int, reason: st

return reply

def get_prevalence(self, request_data: dict):
reply = self._http_request(method='POST', json_data={'request_data': request_data}, headers=self._headers)
return json.loads(reply) # TODO should be change once the XDR fix it on their side


def report_incorrect_wildfire_command(client: Client, args) -> CommandResults:
file_hash = args.get('file_hash')
Expand All @@ -69,6 +81,59 @@ def report_incorrect_wildfire_command(client: Client, args) -> CommandResults:
)


def handle_prevalence_command(client: Client, command: str, args: dict):
key_names_in_response = {
'ip': 'ip_address',
'domain': 'domain_name',
'process': 'process_name',
'cmd': 'process_command_line',
'hash': 'sha256',
'registry': 'key_name'
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PEP8

Suggested change
'registry': 'key_name'
'registry': 'key_name',

}
args.pop('integration_context_brand', None)
args.pop('integration_name', None)
if command == 'core-get-registry-analytics-prevalence':
# arg list should in the following structure:
# args: [
# {"key_name": "some_key1", "value_name": "some_value1"},
# {"key_name": "some_key2", "value_name": "some_value2"}
# ]

args_list = []
keys = argToList(args.get('key_name'))
values = argToList(args.get('value_name'))
if len(keys) != len(values):
raise DemistoException('Number of elements in key_name argument should be equal to the number '
'of elements in value_name argument.')
for i in range(len(keys)):
args_list.append({'key_name': keys[i], 'value_name': values[i]})
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is python, not C.

Suggested change
for i in range(len(keys)):
args_list.append({'key_name': keys[i], 'value_name': values[i]})
for key, value in zip(keys, values):
args_list.append({'key_name': key, 'value_name': value})

else:
args_list = []
for key, value in args.items():
values = argToList(value)
for val in values:
args_list.append({key: val})

request_body = {
'api_id': command,
'args': args_list
}
res = client.get_prevalence(request_body).get('results', [])
command_type = PREVALENCE_COMMANDS[command]
return CommandResults(
readable_output=tableToMarkdown(string_to_table_header(f'{command_type} Prevalence'),
[{
key_names_in_response[command_type]: item.get('args', {}).get(
key_names_in_response[command_type]),
'Prevalence': item.get('value')
} for item in res],
headerTransform=string_to_table_header),
outputs_prefix=f'{INTEGRATION_CONTEXT_BRAND}.AnalyticsPrevalence.{command_type.title()}',
outputs=res,
raw_response=res,
)


def main(): # pragma: no cover
"""
Executes an integration command
Expand All @@ -81,6 +146,8 @@ def main(): # pragma: no cover
api_key = demisto.params().get('apikey')
api_key_id = demisto.params().get('apikey_id')
url = demisto.params().get('url')
url_suffix = '/xsiam/' if command in PREVALENCE_COMMANDS else "/public_api/v1"

if not api_key or not api_key_id or not url:
headers = {
"HOST": demisto.getLicenseCustomField("Core.ApiHostName"),
Expand All @@ -97,7 +164,7 @@ def main(): # pragma: no cover
}
add_sensitive_log_strs(api_key)

base_url = urljoin(url, '/public_api/v1')
base_url = urljoin(url, url_suffix)
proxy = demisto.params().get('proxy')
verify_cert = not demisto.params().get('insecure', False)

Expand Down Expand Up @@ -372,6 +439,9 @@ def main(): # pragma: no cover
elif command == 'core-get-dynamic-analysis':
return_results(get_dynamic_analysis_command(client, args))

elif command in PREVALENCE_COMMANDS:
return_results(handle_prevalence_command(client, command, args))

except Exception as err:
demisto.error(traceback.format_exc())
return_error(str(err))
Expand Down
142 changes: 141 additions & 1 deletion Packs/Core/Integrations/CortexCoreIR/CortexCoreIR.yml
Expand Up @@ -3088,6 +3088,146 @@ script:
- contextPath: Core.DynamicAnalysis.osSpawnerSigner
description: ''
type: String
- arguments:
- default: false
description: The sha256 of a file.
isArray: true
name: sha256
required: true
secret: false
deprecated: false
description: Get the prevalence of a file, identified by sha256.
execution: false
hidden: false
name: core-get-hash-analytics-prevalence
outputs:
- contextPath: Core.AnalyticsPrevalence.Hash.value
description: Whether the hash is prevalent or not.
type: Boolean
- contextPath: Core.AnalyticsPrevalence.Hash.data.global_prevalence
description: The global prevalence of the hash.
type: Unknown
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

update all output typing (unless they are not simple types)

- contextPath: Core.AnalyticsPrevalence.Hash.data.local_prevalence
description: The local prevalence of the hash.
type: Unknown
- arguments:
- default: false
description: The IP address.
isArray: true
name: ip_address
predefined:
- ''
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
predefined:
- ''

required: true
secret: false
deprecated: false
description: Get the prevalence of an ip, identified by ip_address.
execution: false
hidden: false
name: core-get-IP-analytics-prevalence
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

commands should be all lower-case.

Suggested change
name: core-get-IP-analytics-prevalence
name: core-get-ip-analytics-prevalence

outputs:
- contextPath: Core.AnalyticsPrevalence.Ip.value
description: Whether the IP address is prevalent or not.
type: Boolean
- contextPath: Core.AnalyticsPrevalence.Ip.data.global_prevalence
description: The global prevalence of the IP.
type: Unknown
- contextPath: Core.AnalyticsPrevalence.Ip.data.local_prevalence
description: The local prevalence of the IP.
type: Unknown
- arguments:
- default: false
description: The domain name.
isArray: true
name: domain_name
required: true
secret: false
deprecated: false
description: Get the prevalence of a domain, identified by domain_name.
execution: false
hidden: false
name: core-get-domain-analytics-prevalence
outputs:
- contextPath: Core.AnalyticsPrevalence.Domain.value
description: Whether the domain is prevalent or not.
type: Boolean
- contextPath: Core.AnalyticsPrevalence.Domain.data.global_prevalence
description: The global prevalence of the domain.
type: Unknown
- contextPath: Core.AnalyticsPrevalence.Domain.data.local_prevalence
description: The local prevalence of the domain.
type: Unknown
- arguments:
- default: false
description: The process name.
isArray: true
name: process_name
required: true
secret: false
deprecated: false
description: Get the prevalence of a process, identified by process_name.
execution: false
hidden: false
name: core-get-process-analytics-prevalence
outputs:
- contextPath: Core.AnalyticsPrevalence.Process.value
description: Whether the process is prevalent or not.
type: Boolean
- contextPath: Core.AnalyticsPrevalence.Process.data.global_prevalence
description: The global prevalence of the process.
type: Unknown
- contextPath: Core.AnalyticsPrevalence.Process.data.local_prevalence
description: The local prevalence of the process.
type: Unknown
- arguments:
- default: false
description: The key name of a registry path.
isArray: true
name: key_name
required: true
secret: false
- default: false
description: The value name of a registry path.
isArray: true
name: value_name
required: true
secret: false
deprecated: false
description: Get the prevalence of a registry_path, identified by key_name, value_name.
execution: false
hidden: false
name: core-get-registry-analytics-prevalence
outputs:
- contextPath: Core.AnalyticsPrevalence.Registry.value
description: Whether the registry is prevalent or not.
type: Boolean
- contextPath: Core.AnalyticsPrevalence.Registry.data.global_prevalence
description: The global prevalence of the registry.
type: Unknown
- contextPath: Core.AnalyticsPrevalence.Registry.data.local_prevalence
description: The local prevalence of the registry.
type: Unknown
- arguments:
- default: false
description: The process command line.
isArray: true
name: process_command_line
required: true
secret: false
deprecated: false
description: Get the prevalence of a process_command_line, identified by process_command_line.
execution: false
hidden: false
name: core-get-cmd-analytics-prevalence
outputs:
- contextPath: Core.AnalyticsPrevalence.Cmd.value
description: Whether the CMD is prevalent or not.
type: Boolean
- contextPath: Core.AnalyticsPrevalence.Cmd.data.global_prevalence
description: The global prevalence of the CMD.
type: Unknown
- contextPath: Core.AnalyticsPrevalence.Cmd.data.local_prevalence
description: The local prevalence of the CDM.
type: Unknown
feed: false
isfetch: false
longRunning: false
Expand All @@ -3096,7 +3236,7 @@ script:
script: '-'
subtype: python3
type: python
dockerimage: demisto/python3:3.10.4.29342
dockerimage: demisto/python3:3.10.4.30607
tests:
- No tests
fromversion: 6.2.0
57 changes: 57 additions & 0 deletions Packs/Core/Integrations/CortexCoreIR/CortexCoreIR_test.py
Expand Up @@ -30,3 +30,60 @@ def test_report_incorrect_wildfire_command(mocker):
}
res = report_incorrect_wildfire_command(client=mock_client, args=args)
assert res.readable_output == f'Reported incorrect WildFire on {file_hash}'


class TestPrevalenceCommands:

def test_get_domain_analytics(self, mocker):
"""
Given:
- A domain name.
When:
- Calling handle_prevalence_command as part of core-get-domain-analytics-prevalence command.
Then:
- Verify response is as expected.
"""
from CortexCoreIR import handle_prevalence_command, Client
mock_client = Client(base_url=f'{Core_URL}/xsiam/', headers={})
mock_res = load_test_data('./test_data/prevalence_response.json')
mocker.patch.object(mock_client, 'get_prevalence', return_value=mock_res.get('domain'))
res = handle_prevalence_command(mock_client, 'core-get-domain-analytics-prevalence',
{'domain': 'some_name'})
assert res.outputs[0].get('value') is True
assert res.outputs[0].get('args', {}).get('domain_name') == 'some_name'

def test_get_ip_analytics(self, mocker):
"""
Given:
- An Ip address.
When:
- Calling handle_prevalence_command as part of core-get-IP-analytics-prevalence command.
Then:
- Verify response is as expected.
"""
from CortexCoreIR import handle_prevalence_command, Client
mock_client = Client(base_url=f'{Core_URL}/xsiam/', headers={})
mock_res = load_test_data('./test_data/prevalence_response.json')
mocker.patch.object(mock_client, 'get_prevalence', return_value=mock_res.get('ip'))
res = handle_prevalence_command(mock_client, 'core-get-IP-analytics-prevalence',
{'ip': 'some ip'})
assert res.outputs[0].get('value') is True
assert res.outputs[0].get('args', {}).get('ip_address') == 'some_ip'

def test_get_registry_analytics(self, mocker):
"""
Given:
- A registry name.
When:
- Calling handle_prevalence_command as part of core-get-registry-analytics-prevalence command.
Then:
- Verify response is as expected.
"""
from CortexCoreIR import handle_prevalence_command, Client
mock_client = Client(base_url=f'{Core_URL}/xsiam/', headers={})
mock_res = load_test_data('./test_data/prevalence_response.json')
mocker.patch.object(mock_client, 'get_prevalence', return_value=mock_res.get('registry'))
res = handle_prevalence_command(mock_client, 'core-get-registry-analytics-prevalence',
{'key_name': 'some key', 'value_name': 'some value'})
assert res.outputs[0].get('value') is True
assert res.outputs[0].get('args', {}).get('key_name') == 'some key'