Cryptosim

CRYPTOSIM gets correlations and correlation's alerts. Integration fetchs alerts to incident according to instance.

Analytics & SIEM · Cryptosim

Details

IDCryptosim
ProviderCRYPTTECH
CategoryAnalytics & SIEM
From Version5.5.0
Docker Imagedemisto/python3:3.12.13.10116658
Supported ModulesAgentix XSIAM

README

CRYPTTECH CRYPTOSIM

CRYPTOSIM meets the SIEM needs of corporations by its unique correlation engine works in memory, capable of hierarchical correlation, supports different correlation techniques, query structure that allows all kinds of data analytics, detects AI based algorithms behavioral anomalies and threat patterns that are not in rule sets.

From the personal devices we use to the most critical governmental substructures, the awareness of the importance of cyber threats in every segment of the digitalized world and the fact that cyber security must be in all areas of our lives becomes more and more obvious.

The massive attacks on the global scale have clearly demonstrated the importance of taking measures against cyber threats and increasing investments on this area.

CRYPTTECH continues to work towards the goal with the mission of developing new, innovative and indigenous technology and products in the increasingly complex cyber security world. CRYPTTECH provides its unique in-memory correlation capability for its SIEM product with its strong correlation system. CRYPTOSIM collects all logs, detects behavioral differences & anomalies and automatically associates them.

More over it can catch APT (Advanced Persistent Threats). CRYPTTECH achieves high performance values for the SIEM product with its NoSQL structure developed by itself. CRYPTOSIM has become one of the most strategic products for perception of threats with its unique correlation features working with rules and machine learning methods

What does this pack do?

  • Gets all correlations from CRPYTOSIM
  • Gets all correlation alerts from CRPYTOSIM
  • Creates incidents from correlation alerts

Use Cases

  1. Fetching alerts based on correlations.
  2. Getting additional information by command parameters.
  3. Searching correlations.

Commands

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

Examples:

  1. !cryptosim-get-correlations limit=100 sortType=desc
  2. !cryptosim-get-correlationalerts startDate=2022-01-01T12:00:00 endDate=2022-01-01T23:59:59 etc.(shown when command is written)

cryptosim-get-correlation-alerts


The command is used to get correlation alerts.

Base Command

cryptosim-get-correlation-alerts

Input

Argument Name Description Required
startDate This denotes the start date of the search period. It must be used in all API fields. E.g.: “startDate”: “2021-04-24T12:00:00”. Required
endDate This denotes the end date of the search period. It must be used in all API fields. E.g.: endDate: “2021-04-24T24:00:00”. Required
showSolved Boolean, show only solved correlations if the parameter is true, otherwise take all correlations. Optional
crrPluginId If user want to take specific correlation, can take it when ID of correlation is given as parameter. Optional
containStr This is used to search for a word specified in the request. (Contains String) E.g.: “containStr”: “Unsuccessful”. Optional
risk The risk level of correlation rules to filter. Default: -1. Default get all. Optional
srcIPPort This used to search the source IP address in the request. E.g.: “srcIPPort”: “127.0.0.1”. Optional
destIPPort This used to search the destination IP address in the request. E.g.: “dest IPPort”: “127.0.0.1”. Optional
srcPort This is used to filter the responses using the source port. E.g.: “srcPort”: “6335”. Optional
destPort This is used to filter the responses using the source port. E.g.: “destPort”: “6335”. Optional
riskOperatorID risk operator name. It can be equal, greaternumber, greaterorequalnumber, lessnumber, lessnumberorequal, notequal. Default: equal. Default is equal. Optional
limit The limit to get how many correlation alerts get. Default: 100. Optional

Context Output

Path Type Description
CorrelationAlerts.Output Dictionary Return StatusCode, Data or ErrorMessage and Outparameters. StatusCode represent html response code. If it is 200, return Data as list of desired Correlation object. If not, return ErrorMessage. OutParameters is empty.

Configuration parameters

  • url — Your server URL (required)
  • credentials — User (required)
  • proxy — Use system proxy settings
  • first_fetch — First Fetch Time (default 1 hour)
  • max_fetch — Max Fetch
  • time_zone — Timezone(as hour)
  • incidentType — Incident type
  • incidentFetchInterval — Incidents Fetch Interval
  • isFetch — Fetch incidents

Commands (2)

  • cryptosim-get-correlation-alerts

    The command is used to get correlation alerts.

  • cryptosim-get-correlations

    The command is used to get the list of active correlations.

from datetime import datetime, timedelta
from CommonServerPython import *
from CommonServerUserPython import *
import traceback
import json
import base64
import urllib3

# Disable insecure warnings
urllib3.disable_warnings()  # pylint: disable=no-member

""" CONSTANTS """

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


class Client(BaseClient):
    def correlation_alerts(self, last_fetch_time=None):
        args = demisto.args()

        end_time = datetime.utcnow() + timedelta(hours=int(demisto.params().get("time_zone_difference", 3)))
        interval_time = end_time - timedelta(minutes=int(demisto.params().get("incidentFetchInterval", 360)))

        formatted_start_time = (
            datetime.strptime(last_fetch_time, DATE_FORMAT)
            + timedelta(hours=int(demisto.params().get("time_zone_difference", 3)))
            if last_fetch_time is not None
            else None
        )

        if last_fetch_time is None or formatted_start_time < interval_time:  # type: ignore
            formatted_start_time = interval_time

        if formatted_start_time >= end_time:  # type: ignore
            formatted_start_time = formatted_start_time - timedelta(  # type: ignore
                minutes=int(demisto.params().get("incidentFetchInterval", 360))
            )

        parameters = {
            "startDate": args.get("startDate", formatted_start_time.isoformat()),  # type: ignore
            "endDate": args.get("endDate", end_time.isoformat()),
            "showSolved": args.get("showSolved", False),
            "crrPluginId": args.get("crrPluginId", -1),
            "containStr": args.get("containStr", None),
            "risk": args.get("risk", -1),
            "srcIPPort": args.get("srcIPPort", None),
            "destIPPort": args.get("destIPPort", None),
            "srcPort": args.get("srcPort", None),
            "destPort": args.get("destPort", None),
            "riskOperatorID": args.get("riskOperatorID", "equal"),
            "limit": int(args.get("limit", "100")),
            "isJsonLog": True,
        }

        return self._http_request("POST", url_suffix="correlationalertswithlogs", data=json.dumps(parameters))

    def correlations(self):
        args = demisto.args()

        limit = str(args.get("limit", "100"))
        limit_url = "limit=" + limit

        sort_type = str(args.get("sortType", "asc"))
        sort_type_url = "sortType=" + sort_type

        base_url = "correlations?"
        api_url = base_url + limit_url + "&" + sort_type_url
        return self._http_request("GET", data={}, url_suffix=api_url)

    def connection_test(self):
        return self._http_request("GET", data={}, url_suffix="correlations?limit=1")


""" COMMAND FUNCTIONS """


def correlation_alerts_command(client: Client):
    # Call the Client function and get the raw response
    result = client.correlation_alerts()
    readable_data = []
    for res in result["Data"]:
        res = res["CorrelationAlert"]
        readable_data.append(
            {
                "ID": res.get("ID", ""),
                "CORRELATIONID": res.get("CORRELATIONID", ""),
                "RULEID": res.get("RULEID", ""),
                "NAME": res.get("NAME", ""),
                "Severity": res.get("RISK", ""),
                "Created At": res.get("EVENTSTARTDATE", ""),
            }
        )
    markdown = tableToMarkdown(
        "Messages", readable_data, headers=["ID", "CORRELATIONID", "NAME", "RULEID", "Severity", "Created At"]
    )
    return CommandResults(
        outputs_prefix="CorrelationAlerts",
        outputs_key_field="",
        readable_output=markdown,
        outputs=result,
    )


def correlations_command(client: Client):
    result = client.correlations()

    readable_data = []
    for res in result["Data"]:
        readable_data.append({"Correlation ID": res.get("CorrelationId", ""), "Correlation Name": res.get("Name", "")})
    markdown = tableToMarkdown("Messages", readable_data, headers=["Correlation ID", "Correlation Name"])

    return CommandResults(
        outputs_prefix="Correlations",
        outputs_key_field="",
        readable_output=markdown,
        outputs=result,
    )


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:
        if client.connection_test().get("StatusCode") == 200:
            message = "ok"
        else:
            raise Exception(f"""StatusCode:
                            {client.correlations().get('StatusCode')},
                            Error: {client.correlations().get('ErrorMessage')}
                            """)
    except DemistoException as e:
        if "401" in str(e):
            message = "Authorization Error: make sure API User and Password is correctly set"
        else:
            raise e
    return message


""" INCIDENT """


def fetch_incidents(client: Client, params):
    max_results = arg_to_number(arg=params.get("max_fetch", 20), arg_name="max_fetch", required=False)

    first_fetch_time = arg_to_datetime(params.get("first_fetch"), "1 hour").strftime(DATE_FORMAT)  # type: ignore

    last_run = demisto.getLastRun()
    last_fetch = last_run.get("last_fetch", first_fetch_time)

    incidentsList = []
    alert_response = client.correlation_alerts(last_fetch_time=last_fetch)
    incident_data = alert_response.get("Data", [])

    for i, inc in enumerate(incident_data):
        if i >= max_results:  # type: ignore
            break

        incident_name = demisto.get(inc, "CorrelationAlert.NAME")
        time_stamp = demisto.get(inc, "CorrelationAlert.CREATEDATE") + "Z"

        severity_level = int(demisto.get(inc, "CorrelationAlert.RISK", -1))
        if severity_level >= 0 and severity_level <= 5:
            severity = 1
        elif severity_level > 5 and severity_level <= 7:
            severity = 2
        elif severity_level > 7 and severity_level <= 9:
            severity = 3
        elif severity_level > 9 and severity_level <= 10:
            severity = 4
        else:
            severity = 0

        # "log" column is stringfyed 'Log' data.
        demisto.get(inc, "Log").pop("log", None)

        incident_object = {**inc["Log"], **inc["CorrelationAlert"]}

        incident = {
            "name": incident_name,
            "occurred": time_stamp,
            "rawJSON": json.dumps(incident_object),
            "severity": severity,
            "type": "Crpyotsim Correlation Alerts",
        }

        incidentsList.append(incident)

        created_incident = datetime.strptime(time_stamp, DATE_FORMAT)
        last_fetch = datetime.strptime(last_fetch, DATE_FORMAT) if isinstance(last_fetch, str) else last_fetch
        if created_incident > last_fetch + timedelta(hours=int(demisto.params().get("time_zone_difference", 3))):
            last_fetch = created_incident + timedelta(milliseconds=10)

    last_fetch = last_fetch.strftime(DATE_FORMAT) if not isinstance(last_fetch, str) else last_fetch
    # Save the next_run as a dict with the last_fetch key to be stored
    next_run = {"last_fetch": last_fetch}

    return next_run, incidentsList


""" HELPERS """


def get_client(params):
    authorization = params.get("credentials").get("identifier") + ":" + params.get("credentials").get("password")
    auth_byte = authorization.encode("utf-8")
    base64_byte = base64.b64encode(auth_byte)
    base64_auth = base64_byte.decode("utf-8")
    authValue = "Basic " + base64_auth

    headers = {"Content-Type": "application/json", "Authorization": authValue}
    # get the service API url
    base_url = urljoin(params.get("url"), "/api/service/")
    proxy = params.get("proxy", False)

    client = Client(base_url=base_url, verify=False, headers=headers, proxy=proxy)
    return client


""" MAIN FUNCTION """


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

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

    demisto.debug(f"Command being called is {demisto.command()}")
    try:
        client = get_client(params)

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

        elif demisto.command() == "cryptosim-get-correlations":
            return_results(correlations_command(client))

        elif demisto.command() == "cryptosim-get-correlation-alerts":
            return_results(correlation_alerts_command(client))

        elif demisto.command() == "fetch-incidents":
            next_run, incidents = fetch_incidents(client, params)
            demisto.error(json.dumps(next_run))
            demisto.error(json.dumps(incidents))
            demisto.setLastRun(next_run)
            demisto.incidents(incidents)

    # Log exceptions and return errors
    except Exception as e:
        demisto.error(traceback.format_exc())  # print the traceback
        return_error(f"""Failed to execute {demisto.command()} command.\nError:\n{str(e)}""")


""" ENTRY POINT """

if __name__ in ("__main__", "__builtin__", "builtins"):  # pragma: no cover
    main()