ResecurityMonitoring

This package allows retrieving asset monitoring results from monitoring tasks that can be configured in Context and Risk platforms.

Data Enrichment & Threat Intelligence · Resecurity

Details

IDResecurityMonitoring
ProviderResecurity
CategoryData Enrichment & Threat Intelligence
From Version6.8.0
Docker Imagedemisto/python3:3.12.13.10116658
Supported ModulesAgentix XSIAM

README

This package allows retrieving asset monitoring results from monitoring tasks that can be configured in Resecurity® CTI and Resecurity® DRM platforms.
This integration was integrated and tested with version 1.01 of ResecurityMonitoring

Configure Resecurity Monitoring in Cortex

Parameter Description Required
Your server URL   True
API Key The API Key to use for connection True
Trust any certificate (not secure)   False
Use system proxy settings   False

Commands

You can execute these commands from the CLI, as part of an automation, or in a playbook.
After you successfully execute a command, a DBot message appears in the War Room with the command details.

resecurity-get-task-monitor-results-data-breaches


Retrieve monitoring results from a specific monitor task

Base Command

resecurity-get-task-monitor-results-data-breaches

Input

Argument Name Description Required
monitor_task_id Monitor Task ID. Required
page Page number. The results will be returned only for specified page if param value is not empty. Optional
page_size Page size. Possible range of values: 1 - 50. Default value is 20. Optional
limit Limit of the records in dataset. Default value is 1000. Optional
mode Affects which results will be included in dataset. Possible values: 1 - only new results, 2 - last results (default value), 3 - all results. Optional

Context Output

Path Type Description
Resecurity.DataBreach.id String Data breach ID
Resecurity.DataBreach.query String The query for which the result was found
Resecurity.DataBreach.detection_date Number Data breach detection date
Resecurity.DataBreach.email String Data breach email
Resecurity.DataBreach.username String Data breach username
Resecurity.DataBreach.password String Data breach password
Resecurity.DataBreach.password_hash String Data breach password hash
Resecurity.DataBreach.salt String Data breach salt
Resecurity.DataBreach.ip String Data breach IP address
Resecurity.DataBreach.source_name String Data breach source name

Command example

!resecurity-get-task-monitor-results-data-breaches monitor_task_id=1 limit=2 mode=2

Context Example

{
    "Resecurity": {
        "DataBreach": [
            {
                "date": "2016-11-04 21:55:00",
                "detection_date": "2023-03-18 13:14:04",
                "email": "email@domain.test",
                "id": 11192938,
                "info": "",
                "ip": "95.112.168.138",
                "password": "",
                "password_hash": "71356c329abee63757ecb3f60b5f90be34ab47caa85d41344cea3f9c92f38eea0313bf60650fe2149e4a2e169d492d9b59a71e97d7331d74caa8b054b448cf04",
                "query": "domain.test",
                "salt": "",
                "source_name": "source1",
                "username": "JMBStarYT"
            },
            {
                "date": "2016-11-30 21:30:00",
                "detection_date": "2023-03-18 13:14:04",
                "email": "email@domain.test",
                "id": 47200407,
                "info": "",
                "ip": "86.178.141.167",
                "password": null,
                "password_hash": "c2f5c61a8ad5dc1ef8c0478617cac76a",
                "query": "domain.test",
                "salt": null,
                "source_name": "source2",
                "username": null
            }
        ]
    }
}

Human Readable Output

Breaches results from task with ID 1

date detection_date email id info ip password password_hash query salt source_name username
2016-11-04 21:55:00 2023-03-18 13:14:04 email@domain.test 11192938   95.112.168.138   71356c329abee63757ecb3f60b5f90be34ab47caa85d41344cea3f9c92f38eea0313bf60650fe2149e4a2e169d492d9b59a71e97d7331d74caa8b054b448cf04 domain.test   source1 JMBStarYT
2016-11-30 21:30:00 2023-03-18 13:14:04 email@domain.test 47200407   86.178.141.167   c2f5c61a8ad5dc1ef8c0478617cac76a domain.test   source2  

Command example

!resecurity-get-task-monitor-results-data-breaches monitor_task_id=1 page_size=2 page=10 mode=2

Context Example

{
    "Resecurity": {
        "DataBreach": [
            {
                "date": "2016-12-07 15:53:00",
                "detection_date": "2023-03-18 13:14:04",
                "email": "test@test.test",
                "id": 361424177,
                "info": "",
                "ip": "",
                "password": "aaaaaa",
                "password_hash": null,
                "query": "test.test",
                "salt": null,
                "source_name": "source3",
                "username": null
            },
            {
                "date": "2016-12-07 15:53:00",
                "detection_date": "2023-03-18 13:14:04",
                "email": "test@test.test",
                "id": 361832967,
                "info": "",
                "ip": "",
                "password": "pppppp",
                "password_hash": null,
                "query": "test.test",
                "salt": null,
                "source_name": "source3",
                "username": null
            }
        ]
    }
}

Human Readable Output

Breaches results from task with ID 1

date detection_date email id info ip password password_hash query salt source_name username
2016-12-07 15:53:00 2023-03-18 13:14:04 test@test.test 361424177     aaaaaa   test.test   source3  
2016-12-07 15:53:00 2023-03-18 13:14:04 test@test.test 361832967     pppppp   test.test   source3  

Configuration parameters

  • url — Your server URL (required)
  • credentials — (required)
  • insecure — Trust any certificate (not secure)
  • proxy — Use system proxy settings

Commands (1)

  • resecurity-get-task-monitor-results-data-breaches

    Retrieve monitoring results from a specific monitor task

from typing import Any

import demistomock as demisto
import urllib3
from CommonServerPython import *  # noqa # pylint: disable=unused-wildcard-import

from CommonServerUserPython import *  # noqa

# Disable insecure warnings
urllib3.disable_warnings()


""" CONSTANTS """

DATE_FORMAT = "%Y-%m-%dT%H:%M:%SZ"  # ISO8601 format with UTC, default in XSOAR

MODULE_NAME_BREACHES = "breaches"

MAPPING: dict = {MODULE_NAME_BREACHES: {"date": "uploadTime", "name": "email", "prefix": "Data Breach"}}

# API Client params
TIMEOUT = 60.0
RETRIES = 4
STATUS_LIST_TO_RETRY = [429, 500]

STATUS_CODE_MSGS = {
    401: "Bad Credentials",
    403: "Forbidden. Something is wrong with your account, please, contact to Resecurity.",
    404: "Not found. There is no such data on server.",
    500: "There are some troubles on server with your request.",
}

DEFAULT_RESULTS_SIZE_LIMIT = 100
DEFAULT_PAGE_SIZE = 50
DEFAULT_MODE = 2  # last results

PAGINATION_HEADER_NAME = "X-Pagination-Page-Count"

""" CLIENT CLASS """


class Client(BaseClient):
    """
    Client class to interact with the service API
    """

    def check_connection(self) -> dict[str, Any]:
        """
        Check connection '/monitor/check-connection' API endpoint
        """
        return self._http_request(
            method="GET",
            url_suffix="/monitor/check-connection",
        )

    def get_task_monitor_results(self, monitor_task_id, module_name: str, page, page_size, mode) -> requests.Response:
        """
        Get monitor task results by module '/monitor/task-results-by-module' API endpoint
        """
        response = self._http_request(
            method="GET",
            url_suffix="/monitor/task-results-by-module",
            resp_type="response",
            params={"id": monitor_task_id, "module_name": module_name, "page": page, "per-page": page_size, "mode": mode},
            timeout=TIMEOUT,
            retries=RETRIES,
            status_list_to_retry=STATUS_LIST_TO_RETRY,
        )

        # check response status
        if response.status_code != 200:
            if response.status_code in STATUS_CODE_MSGS:
                raise DemistoException(STATUS_CODE_MSGS[response.status_code])
            else:
                raise DemistoException(f"Status code {response.status_code} for API request")

        return response


""" HELPER FUNCTIONS """


def get_human_readable_output(module_name, monitor_task_id, result):
    return tableToMarkdown(
        name=f"{module_name} results from task with ID {monitor_task_id}",
        t=result,
        removeNull=True,
        date_fields=["detection_date"],
    )


""" COMMAND FUNCTIONS """


def test_module(client: Client) -> str:
    """Tests API connectivity and authentication'

    Returning 'ok' indicates that the integration works like it is supposed to.
    Connection to the service is successful.
    Raises exceptions if something goes wrong.

    :type client: ``Client``
    :param Client: client to use

    :return: 'ok' if test passed, anything else will fail the test.
    :rtype: ``str``
    """

    message: str = ""
    try:
        result = client.check_connection()
        if result.get("message") == "ok":
            return "ok"
        else:
            raise DemistoException("Failed to establish connection with provided credentials.")
    except DemistoException as e:
        if "Forbidden" in str(e) or "Authorization" in str(e):
            message = "Authorization Error: make sure API Key is correctly set"
        else:
            raise e
    return message


def get_task_monitor_results_command(module_name: str):
    """_summary_

    Args:
        module_name (str): _description_
    """

    def get_task_monitor_results(client: Client, args: dict) -> CommandResults:
        # get params from user
        monitor_task_id = arg_to_number(args.get("monitor_task_id"), "monitor_task_id", True)
        limit = arg_to_number(args.get("limit", DEFAULT_RESULTS_SIZE_LIMIT))
        page = arg_to_number(args.get("page"))
        page_size = arg_to_number(args.get("page_size", DEFAULT_PAGE_SIZE))
        mode = arg_to_number(args.get("mode", DEFAULT_MODE))

        if page is not None:
            # request data from specific page
            response = client.get_task_monitor_results(monitor_task_id, module_name, page, page_size, mode)

            result = response.json()
        else:
            # request data from many pages
            page = 1

            # limit 'page size' value if it is bigger that 'limit' value
            if limit is not None and page_size is not None and page_size > limit:
                page_size = limit
            result_count = 0

            result = []
            while limit is not None and result_count < limit:
                response = client.get_task_monitor_results(monitor_task_id, module_name, page, page_size, mode)

                total_pages = response.headers.get(PAGINATION_HEADER_NAME)
                if not total_pages:
                    demisto.debug(total_pages)
                    raise DemistoException(f"Something is wrong, header {PAGINATION_HEADER_NAME} is empty for API request")
                total_pages = int(total_pages)

                result += response.json()
                result_count = len(result)
                page += 1

                if page > total_pages:
                    break

        # compose result data
        return CommandResults(
            outputs_prefix=f"Resecurity.{MAPPING.get(module_name, {}).get('prefix', '').replace(' ', '')}",
            outputs_key_field="id",
            outputs=result[:limit],
            readable_output=get_human_readable_output(MAPPING.get(module_name, {}).get("prefix"), monitor_task_id, result),
            raw_response=result,
            ignore_auto_extract=True,
        )

    return get_task_monitor_results


""" MAIN FUNCTION """


def main() -> None:
    """main function, parses params and runs command functions

    :return:
    :rtype:
    """
    params = demisto.params()
    args = demisto.args()
    command = demisto.command()

    # get API key
    api_key = params.get("credentials", {}).get("password")

    # get the service API URL
    base_url = urljoin(params["url"], "/api")

    # if your Client class inherits from BaseClient, SSL verification is
    # handled out of the box by it, just pass ``verify_certificate`` to
    # the Client constructor
    verify_certificate = not params.get("insecure", False)

    # if your Client class inherits from BaseClient, system proxy is handled
    # out of the box by it, just pass ``proxy`` to the Client constructor
    proxy = params.get("proxy", False)

    demisto.debug(f"Command being called is {demisto.command()}")
    try:
        # Add the proper headers for authentication
        headers: dict = {}

        client = Client(base_url=base_url, verify=verify_certificate, auth=(api_key, ""), headers=headers, proxy=proxy)

        # command cases implementation
        commands = {"resecurity-get-task-monitor-results-data-breaches": get_task_monitor_results_command(MODULE_NAME_BREACHES)}

        if command == "test-module":
            # This is the call made when pressing the integration Test button.
            result = test_module(client)
            return_results(result)

        elif command in commands:
            return_results(commands[command](client, args))
        else:
            raise NotImplementedError(f"Command {command} is not implemented.")

    # Log exceptions and return errors
    except Exception as e:
        return_error(f"Failed to execute {demisto.command()} command.\nError:\n{e!s}")


""" ENTRY POINT """


if __name__ in ("__main__", "__builtin__", "builtins"):
    main()