LogsignSiem
Logsign SIEM provides to collect and store unlimited data, investigate and detect threats, and respond automatically.
Analytics & SIEM · Logsign SIEM
Details
| ID | LogsignSiem |
|---|---|
| Provider | Logsign |
| Category | Analytics & SIEM |
| From Version | 6.0.0 |
| Docker Image | demisto/python3:3.12.13.10116658 |
| Supported Modules | Agentix XSIAM |
README
Logsign SIEM provides comprehensive visibility and control of your data lake by allowing security analysts to collect and store unlimited data, investigate and detect threats, and respond automatically.
This integration was integrated and tested with version 4.6.x of Logsign SIEM
Configure Logsign SIEM in Cortex
| Parameter | Description | Required |
|---|---|---|
| Server URL (e.g. https://192.168.0.1) | Logsign SIEM API URL | True |
| API Key | The API Key to use for connection | True |
| Trust any certificate (not secure) | False | |
| Use system proxy settings | False | |
| Last Run Time (ISO8601 format with UTC) | Last run time format like ‘%Y-%m-%dT%H:%M:%SZ’ | True |
| First Fetch Time (default 1 hour) | First Fetch Time (e.g 1 hour) | False |
| isFetch | False | |
| Max Fetch | Maximum number of incidents per fetch (Recommended less than 200) | 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.
logsign-fetch-incidents
Gets Incidents from Logsign SIEM
Base Command
logsign-fetch-incidents
Input
| Argument Name | Description | Required |
|---|---|---|
| last_run | Last Run Fomat: ‘%Y-%m-%dT%H:%M:%SZ’. Possible values are: . | Required |
| query | Lucene query support | Optional |
Context Output
| Output Path | Type | Description |
|---|---|---|
| Logsign.Incidents.Severity.Name | String | Incident Severity |
| Logsign.Incidents.Time.Generated | date | Time Generation of incident |
| Logsign.Incidents.EventMap.Context | String | Context of Event |
| Logsign.Incidents.Event.Category | String | Category of triggered event |
| Logsign.Incidents.EventSource.IP | unknown | The eventsource addresses that are associated with the incident |
| Logsign.Incidents.Destination.IP | unknown | The destination addresses that are associated with the incident |
| Logsign.Incidents.Source.IP | unknown | The source addresses that are associated with the incident |
| Logsign.Incidents.Destination.Port | unknown | Destination Port |
| Logsign.Incidents.Source.Port | unknown | Source Port |
| Logsign.Incidents.Alert.Category | String | Category of Incident |
| Logsign.Incidents.Alert.Info | String | Incident Description |
| Logsign.Incidents.Alert.AlertUID | Number | ID of Incident |
| Logsign.Incidents.Alert.TriggerEventID | Number | Trigger Event ID |
| Logsign.Incidents.EventSource.HostName | String | The eventsource hostname that are associated with the incident |
Command Example
!logsign-fetch-incidents last_run=2021-07-27T10:27:00Z
Context Example
{
"success": true,
"incidents": [
{
"Packets": {
"Total": 2,
"Sent": 1,
"Received": 1
},
"Bytes": {
"Total": 124,
"Sent": 60,
"Received": 64
},
"Severity": {
"ID": 4,
"Name": "warning"
},
"Time": {
"Generated": "2021-07-27 10:35:33",
"Start": "2021-07-27 10:26:40",
"Received": "2021-07-27 10:35:33"
},
"EventMap": {
"Context": "Network",
"Type": "Session",
"SubType": "Allow",
"ID": 60101,
"Info": "Network Connection Allow"
},
"Event": {
"VendorID": 2,
"SystemID": 30292,
"Action": "allow",
"SubCategory": "end",
"Reason": "tcp-rst-from-server",
"Category": "TRAFFIC",
"TrackID": "2c60f28a"
},
"EventSource": {
"IP": "10.x.x.1",
"Serial": "001801044448",
"Vendor": "PaloAlto",
"Type": "Security System",
"Category": "Firewall",
"PrefixID": 3029,
"HostName": "PA-3020",
"Description": "PaloAlto",
"Collector": "alert.flow"
},
"Session": {
"RepeatCount": "1",
"ID": "137290"
},
"Application": {
"Name": "incomplete"
},
"Destination": {
"IP": "193.x.x.6",
"City": "Istanbul",
"Country": "Turkey",
"Interface": "ethernet1/3.100",
"Port": 80,
"Zone": "LogsignServers",
"NatIP": "10.x.x.10",
"NatPort": 80,
"Location": "Unknown",
"Position": "in"
},
"Source": {
"IP": "183.x.x.14",
"Country": "China",
"Interface": "ethernet1/12",
"Port": 21089,
"Zone": "untrust",
"NatIP": "183.x.x.14",
"NatPort": 21089,
"Location": "Unknown",
"Position": "out"
},
"URL": {
"Category": "any"
},
"Protocol": {
"Name": "TCP"
},
"Rule": {
"Name": "IsmailLogsign"
},
"Details": {
"EndReason": "tcp-rst-from-server"
},
"DataType": "alert",
"rawmsg": "Jul 27 10:26:44 PA-3020 1,2021/07/27 10:26:44,001801044448,TRAFFIC,end,2304,2021/07/27 10:26:44,183.136.225.14,193.192.118.6,183.136.225.14,10.10.100.2,IsmailLogsign,,,incomplete,vsys1,untrust,LogsignServers,ethernet1/12,ethernet1/3.100,LogsignSyslogProfile,2021/07/27 10:26:44,137290,1,21089,80,21089,80,0x40401b,tcp,allow,124,60,64,2,2021/07/27 10:26:40,0,any,0,2622656518,0x0,China,Turkey,0,1,1,tcp-rst-from-server,0,0,0,0,,PA-3020,from-policy,,,0,,0,,N/A,0,0,0,0,1cf61932-8145-4fd8-8d01-7a410f782236,0",
"Internal": {
"IP": "193.x.118.6"
},
"External": {
"IP": "183.x.225.14"
},
"Intelligence": {
"IP": "183.x.225.14",
"Info": "Attack Info",
"ListID": 1029,
"Type": "Attack"
},
"Context": {
"SourceIP": [
"Suspicious"
]
},
"Behavior": {
"SourceIP": [
"Threat Intelligence IPs"
]
},
"_insert_time": 1627371333,
"Alert": {
"Category": "Threat Intelligence",
"Info": "Threat Intelligence Host Allowed Connection to Internal Network",
"AlertUID": "bd966ac24e90168f14df453a5e1ba6a0",
"TriggerEventID": "c459a1931fa3409bb59f9c35120021f9",
"Reason": "EventMap.Type:Session\nEventMap.SubType:Allow\nDestination.Position:in\nBehavior.SourceIP:Threat Intelligence IPs"
},
"Action": {
"Object": "183.x.225.14",
"CoManaged": "collect",
"FeedList": "ip"
},
"_es_type": "flow@alert@generic_log"
}
]
}
Human Readable Output

logsign-get-columns-query
Gets column values based on your lucene query
Base Command
logsign-get-columns-query
Input
| Argument Name | Description | Required |
|---|---|---|
| query | Query Description. | Required |
| grouped_column | Group Column . | Required |
| criteria | Criteria Value. Possible values are: unique, value. | Required |
| time_frame | Time Frame (e.g 1 hour). | Required |
Context Output
| Path | Type | Description |
|---|---|---|
| LogsignSiem.Columns | Unknown | Column list returned as the result of the query |
Command Example
!logsign-get-columns-query criteria="value" grouped_column="Source.IP" query="*" time_frame="1 day"
Context Example
{
"Logsign SIEM": {
"Columns": {
"columns": [
"192.x.1.35",
"192.x.1.17",
"192.x.1.18",
"192.x.1.5",
"192.x.1.93"
]
}
}
}
Human Readable Output
Results
columns 192.168.1.35,
192.168.1.17,
192.168.1.18,
192.168.1.5,
192.168.1.93
logsign-get-count-query
Gets count of column values.
Base Command
logsign-get-count-query
Input
| Argument Name | Description | Required |
|---|---|---|
| query | Query. | Required |
| grouped_column | Grouped Column. | Required |
| criteria | Criteria Value. Possible values are: unique, value. | Required |
| time_frame | Time Frame. | Required |
Context Output
| Path | Type | Description |
|---|---|---|
| LogsignSiem.Count | Number | Count number returned as the result of the query |
Command Example
!logsign-get-count-query criteria="value" grouped_column="Source.IP" query="*" time_frame="1 day"
Context Example
{
"Logsign SIEM": {
"Count": {
"count": 785554
}
}
}
Human Readable Output
Results
count 785554
Configuration parameters
url— Server URL (e.g. https://192.168.0.1) (required)apikey— API Key (required)insecure— Trust any certificate (not secure)proxy— Use system proxy settingsfirst_fetch— First Fetch Time (default 1 hour)max_fetch— Max FetchincidentType— Incident typeincidentFetchInterval— Incidents Fetch IntervalisFetch— Fetch incidentsquery— Query
Commands (2)
-
logsign-get-columns-queryQuery for columns.
-
logsign-get-count-queryGet Count Query.
from datetime import datetime, timedelta import demistomock as demisto # noqa: F401 import urllib3 from CommonServerPython import * # noqa: F401 from CommonServerUserPython import * # Disable insecure warnings urllib3.disable_warnings() # pylint: disable=no-member """ CONSTANTS """ DATE_FORMAT: str = "%Y-%m-%dT%H:%M:%SZ" # ISO8601 format with UTC, default in XSOAR DATE_FORMAT_WITH_MICROSECOND = "%Y-%m-%dT%H:%M:%S.%fZ" LOGSIGN_INC_DATE_FORMAT = "%Y-%m-%d %H:%M:%S" DEFAULT_FETCH_LIMIT = 50 DEFAULT_FIRST_FETCH = "1 hour" CONTENT_TYPE_JSON = "application/json" API_VERSION = "v1.0" INTEGRATION_VERSION = "v1.0" URL_SUFFIX: dict[str, str] = { "FETCH_INCIDENTS": "get_incidents", "GET_COLUMN": "get_columns", "GET_COUNT": "get_count", "TEST_API": "test_api", } class Client(BaseClient): def __init__(self, url: str, api_key: str, verify: bool, proxy: bool): """ :type url: ``str`` :param url: Base url of API Endpoint :type api_key: ``str`` :param api_key: API Key :type verify: ``bool`` :param verify: Whether the request should verify the SSL certificate. :type proxy: ``bool`` :param proxy: Whether to run the integration using the system proxy. """ self._api_key = api_key self._proxies = proxy super().__init__(base_url=url, verify=verify, proxy=self._proxies) def get_incidents(self, method: str, last_run: Any, query: str) -> Any: """ Get-Incidents Service :type method: ``str`` :param method: The HTTP method, for example: GET, POST, and so on. :type last_run: ``str`` :param last_run: The greatest incident created_time we fetched from last fetch :type query: ``str`` :param query: Query :return: Depends on the resp_type parameter :rtype: ``dict`` or ``str`` or ``requests.Response`` """ try: last_run = datetime.strftime(last_run, DATE_FORMAT) except Exception: raise ValueError("last_run type is not datetime format") return self._http_request( method=method, url_suffix=URL_SUFFIX["FETCH_INCIDENTS"], params={"api_key": self._api_key, "last_run": last_run, "query": query if query is not None else ""}, ) def get_query(self, method: str, query: str, url_suffix: str, grouped_column: str, criteria: str, time_frame: str): """ Get-Query Service :type method: ``str`` :param method: The HTTP method, for example: GET, POST, and so on. :type query: ``str`` :param query: Elastic search query for LogsignSiem Search Engine. :type url_suffix: ``str`` :param url_suffix: The API endpoint. :type grouped_column: ``str`` :param grouped_column: GroupedColumn (e.g. Source.IP) :type criteria: ``str`` :param criteria: Criteria [value or unique] :type time_frame: ``str`` :param time_frame: TimeFrame [min, hour, day] (e.g 1 day) :return: Depends on the resp_type parameter :rtype: ``dict`` or ``str`` or ``requests.Response`` """ return self._http_request( method=method, url_suffix=url_suffix, params={ "api_key": self._api_key, "query": query, "grouped_column": grouped_column, "criteria": criteria, "time_frame": time_frame, }, ) def test_api(self, method: str, url_suffix: str) -> Any: """ Test API Service :type method: ``str`` :param method: The HTTP method, for example: GET, POST, and so on. :type url_suffix: ``str`` :param url_suffix: The API endpoint. :return: Depends on the resp_type parameter :rtype: ``dict`` or ``str`` or ``requests.Response`` """ return self._http_request(method=method, url_suffix=url_suffix, params={"api_key": self._api_key}) def get_datetime_now(first_fetch_time): """ Get Datetime Now ISO8601 format with UTC """ now = datetime.now() - timedelta(hours=int(first_fetch_time.split()[0])) return now.strftime(DATE_FORMAT) def api_check_command(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`` """ try: client.test_api("GET", URL_SUFFIX["TEST_API"]) except Exception: raise ValueError("Authorization Error: Make sure Logsign Discovery API Key is correctly set") return "ok" def check_arg(key: str, args: dict[str, Any]) -> Any: """ Check Arg Service :type key: ``str`` :param key: Check arg in dict :type args: ``dict`` :param args: Args dict (e.g {key: value}) :return: Depends on the key parameter :rtype: ``dict`` or ``str`` or ``list`` """ tmp = args.get(key, None) if not tmp: raise ValueError(f"{key} not specified!") return tmp def get_generic_data(data: dict[str, Any], key: str, output_prefix: str) -> CommandResults: """ Get Generic Data Service :type data: ``dict`` :param data: incidents json data :type key: ``str`` :param key: query service type (e.g column, count) :type output_prefix: ``str`` :param output_prefix: output_prefix for HumanCommandResult (e.g Logsign.Incident, Logsign.Count) :rtype: ``CommandResults` :return CommandResults: use to return results to warroom """ result = {key: check_arg(key, data)} return CommandResults(outputs_prefix=output_prefix, outputs=result, raw_response=json.dumps(data)) def fetch_incidents(client: Client, first_fetch: str, max_fetch: int, query: str) -> tuple[dict[str, str], list[dict]]: """ This function is called for fetching incidents. :type client: ``Client`` :param Client: Client object :type first_fetch: ``str`` :param first_fetch: Example: "1 hour" :type max_fetch: ``int`` :param max_fetch: Maximum number of incidents per fetch (Recommended less than 200) :type query: ``str`` :param query: Example: Alert.AlertUID:1 Action.Object:1 ... :rtype: ``Tuple[Dict[str, int], List[dict]]`` :return next_run: This will be last_run in the next fetch-incidents :return incidents: Incidents that will be created in Cortex XSOAR """ last_run = demisto.getLastRun() last_fetch = last_run.get("last_fetch", None) if last_fetch is None: last_fetch = datetime.utcnow() - timedelta(hours=int(first_fetch.split()[0])) else: last_fetch = datetime.strptime(last_fetch, DATE_FORMAT) latest_created_time = last_fetch data = client.get_incidents(method="GET", last_run=last_fetch, query=query) incidents: list[dict[str, Any]] = [] for incident in data["incidents"]: # convert the date to ISO8601 created_at_str = f"{datetime.strptime(incident['Time']['Generated'], LOGSIGN_INC_DATE_FORMAT).isoformat()}Z" created_at_dt = datetime.strptime(created_at_str, DATE_FORMAT) inc = {"name": f"Logsign-{created_at_str}", "occured": created_at_str, "rawJSON": json.dumps(incident)} incidents.append(inc) latest_created_time = created_at_dt if len(incidents) >= max_fetch: break # Save the next_run as a dict with the last_fetch key to be stored next_run = {"last_fetch": datetime.strftime(latest_created_time, DATE_FORMAT)} return next_run, incidents def get_query_command(client: Client, url_suffix: str, args: dict[str, Any]) -> CommandResults: """ This function is called for query commands. :type client: ``Client`` :param Client: Client object :type url_suffix: ``str`` :param url_suffix: The API endpoint. :type args: ``dict`` :param args: Command args :rtype: ``CommandResults` :return CommandResults: use to return results to warroom """ query = check_arg("query", args) grouped_column = check_arg("grouped_column", args) criteria = check_arg("criteria", args) time_frame = check_arg("time_frame", args) response = client.get_query("GET", query, url_suffix, grouped_column, criteria, time_frame) result = CommandResults() if url_suffix == URL_SUFFIX["GET_COUNT"]: result = get_generic_data(response, "count", "LogsignSiem.Count") elif url_suffix == URL_SUFFIX["GET_COLUMN"]: result = get_generic_data(response, "columns", "LogsignSiem.Columns") return result def main() -> None: """main function, parses params and runs command functions :return: :rtype: """ command = demisto.command() demisto.info(f"[Logsign] Command being called is {command}") try: params = demisto.params() base_url = params.get("url") verify_certificate = params.get("insecure", False) proxy = params.get("proxy", False) first_fetch = params.get("first_fetch") first_fetch_time = first_fetch if first_fetch else DEFAULT_FIRST_FETCH api_key = params.get("apikey") query = params.get("query", "") max_fetch = params.get("max_fetch") max_fetch = DEFAULT_FETCH_LIMIT if not params.get("max_fetch") else int(max_fetch) client = Client(url=base_url, api_key=api_key, verify=verify_certificate, proxy=proxy) args = demisto.args() if command == "fetch-incidents": last_run, incidents = fetch_incidents(client, first_fetch_time, max_fetch, query) demisto.setLastRun(last_run) demisto.incidents(incidents) elif command == "logsign-get-columns-query": return_results(get_query_command(client, URL_SUFFIX["GET_COLUMN"], args)) elif command == "logsign-get-count-query": return_results(get_query_command(client, URL_SUFFIX["GET_COUNT"], args)) elif command == "test-module": result = api_check_command(client) return_results(result) except Exception as e: demisto.error(traceback.format_exc()) return_error(f"Error: {e!s}") if __name__ in ("__main__", "__builtin__", "builtins"): main()