Inception
Stairwell Inception is a security intelligence engine that automates the continuous capture, storage, and of executable files and other primary security artifacts to improve detection and response against advanced attacks that evade traditional security tools.
Data Enrichment & Threat Intelligence · Stairwell
Details
| ID | Inception |
|---|---|
| Provider | Stairwell |
| Category | Data Enrichment & Threat Intelligence |
| From Version | 6.5.0 |
| Docker Image | demisto/python3:3.12.13.10116658 |
| Supported Modules | Agentix XSIAM |
README
Use the Stairwell Inception integration to enrich data in XSOAR using Stairwell’s knowledge and perform automated variant discovery.
Not a customer and interested in signing up? You can request access here.
Generate required API key
Follow these steps for a self-deployed configuration.
- Access the Inception web UI and generate a API/CLI token here.
- Copy your API token for the integration configuration usage.
Configure Stairwell Inception in Cortex
| Parameter | Required |
|---|---|
| API Key | True |
| Use system proxy settings | False |
| Trust any certificate (not secure) | 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.
inception-file-enrichment
Enrich files using file hash (MD5, SHA1, SHA256) with Stairwell’s knowledge.
Base Command
inception-file-enrichment
Input
| Argument Name | Description | Required |
|---|---|---|
| fileHash | File hash (MD5, SHA1, SHA256) to lookup. | Required |
Context Output
| Path | Type | Description |
|---|---|---|
| Inception.File_Details | Dict | Raw JSON output from API |
Command Example
!inception-file-enrichment fileHash=9fe1ac46f0cdebf03156a6232d771c14559f8daf
Context Example
{
"inception": {
"file_details": {
"type": "file",
"id": "e7762f90024c5366807c7c145d3456f0ac3be086c0ec3557427d3c2c10a2052d",
"links": {
"self": "/api/v3/files/e7762f90024c5366807c7c145d3456f0ac3be086c0ec3557427d3c2c10a2052d"
},
"data": {
"attributes": {
"md5": "00ddbafe247c891eed36bd74f66f936b",
"sha1": "9fe1ac46f0cdebf03156a6232d771c14559f8daf",
"sha256": "e7762f90024c5366807c7c145d3456f0ac3be086c0ec3557427d3c2c10a2052d",
"size": 118024,
"creation_date": 1653722032,
"last_analysis_results": {
"ClamAV": {
"category": "undetected",
"engine_name": "ClamAV",
"result": "undetected"
},
"Engine2": {
"category": "malicious",
"engine_name": "Engine2",
"result": "Trojan/Win.Hermeticwiper"
}
},
"last_analysis_stats": {
"harmless": 1,
"malicious": 1
},
"names": [
"C:\\GimmeCreds.dll"
],
"meaningful_name": "C:\\GimmeCreds.dll",
"type_description": "EXE",
"crowdsourced_yara_results": [{
"rule_name": "wiper_HermeticWiper"
},
{
"rule_name": "MAL_HERMETIC_WIPER"
}
],
"inception": {
"environments": [{
"environment_id": {
"id": "AAAAAA-BBBBBB-CCCCCC-DDDDDDD"
}
}],
"assets": [{
"asset_id": {
"id": "DDDDDD-CCCCCC-BBBBBB-AAAAAAA"
},
"name": "WORKGROUP\\IDABEAR"
}]
},
"magic": "EXE",
"imphash": "fe4a2284122da348258c83ef437fbd7b",
"ssdeep": "1536:WBOoa7Nn54urilmw9BgjKu1sPPxaS4NOyqC:WBOoa7P4xlPwV16PkS4NVqC"
}
}
}
}
}
Human Readable Output
Stairwell Inception
MD5: 00ddbafe247c891eed36bd74f66f936b
SHA256: e7762f90024c5366807c7c145d3456f0ac3be086c0ec3557427d3c2c10a2052d
Seen Assets: 1
Matching YARA Intel: wiper_HermeticWiper,MAL_HERMETIC_WIPERAV Scanning Results
Engine Name Result ClamAV undetected Engine2 Trojan/Win.Hermeticwiper
inception-variant-discovery
Hunt for variants using a SHA256 across all files you have access to, including your environments and Stairwell’s malware feeds.
Base Command
inception-variant-discovery
Input
| Argument Name | Description | Required |
|---|---|---|
| sha256 | SHA256 of file to hunt for variants on. | Required |
Context Output
| Path | Type | Description |
|---|---|---|
| Inception.Variants | Dict | Raw JSON output from API |
Command Example
!inception-variant-discovery sha256=30e27357b7b773b226d4ee638e17b19b954226d197b0781822859269a5c22b4d
Context Example
{
"inception": {
"variants": {
"name": "variants/30e27357b7b773b226d4ee638e17b19b954226d197b0781822859269a5c22b4d",
"variants": [{
"similarity": 1,
"sha256": "e1a00d8923bac6f863c262236f15eb60d80571f8b31e7220c4b2912fae7e9a14"
},
{
"similarity": 0.9875,
"sha256": "d2a00d8923bac6f863c262236f15eb60d80571f8b31e7220c4b2912fae7e9a12"
}
],
"variant_count": 2,
"original_object": "30e27357b7b773b226d4ee638e17b19b954226d197b0781822859269a5c22b4d"
}
}
}
Human Readable Output
File Variants Discovered
sha256 similarity e1a00d8923bac6f863c262236f15eb60d80571f8b31e7220c4b2912fae7e9a14 1 d2a00d8923bac6f863c262236f15eb60d80571f8b31e7220c4b2912fae7e9a12 0.9875
Configuration parameters
apikey— (required)proxy— Use system proxy settingsinsecure— Trust any certificate (not secure)
Commands (2)
-
inception-file-enrichmentEnrich files using file hash (MD5, SHA1, SHA256).
-
inception-variant-discoveryDiscover variants using a file hash (SHA256).
import json import demistomock as demisto import urllib3 from CommonServerPython import * # noqa # pylint: disable=unused-wildcard-import from CommonServerUserPython import * # noqa # pylint: disable=unused-wildcard-import urllib3.disable_warnings() # pylint: disable=no-member class Client(BaseClient): def get_file_reputation(self, file_hash: str) -> Dict[str, Any]: return self._http_request(method="GET", url_suffix=file_hash) def get_file_variants( self, file_hash: str, ) -> Dict[str, Any]: return self._http_request(method="GET", url_suffix=file_hash) def test_module(client): # pragma: no cover try: # We'll use a default file hash, accessible by all, to test the connection response = client.get_file_reputation("e7762f90024c5366807c7c145d3456f0ac3be086c0ec3557427d3c2c10a2052d") response = json.dumps(response) if "attributes" in response: return "ok" except Exception: return "Authorization Error: make sure API Key is correctly set" def file_enrichment_command(client, file_hash): try: responseJson = client.get_file_reputation(file_hash) if "attributes" in responseJson["data"]: md = "# Stairwell Inception\n" file_md5 = responseJson["data"]["attributes"]["md5"] file_sha1 = responseJson["data"]["attributes"]["sha1"] file_sha256 = responseJson["data"]["attributes"]["sha256"] md += f"MD5: {file_md5}\n" md += f"SHA1: {file_sha1}\n" md += f"SHA256: {file_sha256}\n" # List the filename(s) if present if responseJson["data"]["attributes"]["names"]: filenames = [] for ind in responseJson["data"]["attributes"]["names"]: if "\\" in ind: full_path = ind.split("\\") filename = full_path[-1].lower() filenames.append(filename) if filename not in filenames else filenames elif "/" in ind: full_path = ind.split("/") filename = full_path[-1].lower() filenames.append(filename) if filename not in filenames else filenames filenames_string = ", ".join([str(x) for x in filenames]) md += f"Filename(s): {filenames_string}\n" # Count the number of assets if there are seen assets if responseJson["data"]["attributes"]["occurrences"]: seen_envs = len(responseJson["data"]["attributes"]["occurrences"]) # Orgs may have multiple environments, especially partners if seen_envs > 1: env_list = [] for indEnv in responseJson["data"]["attributes"]["occurrences"]: asset_count = len(indEnv["assets"]) envName = indEnv["environment"]["name"] seen_str = envName + "(" + str(asset_count) + ")" env_list.append(seen_str) env_string = ", ".join([str(x) for x in env_list]) md += f"Seen_Assets: {env_string}\n" else: seen_assets = len(responseJson["data"]["attributes"]["occurrences"][0]["assets"]) seen_env = responseJson["data"]["attributes"]["occurrences"][0]["environment"]["name"] md += f"Seen Assets: {seen_env}({seen_assets})\n" # Show matching YARA intelligence if present if responseJson["data"]["attributes"]["crowdsourced_yara_results"]: yara_rules = [] for yara in responseJson["data"]["attributes"]["crowdsourced_yara_results"]: yara_rules.append(yara["rule_name"]) yara_string = ", ".join([str(x) for x in yara_rules]) md += f"Matching YARA Intel: {yara_string}\n" # Show Mal-Eval result mal_eval_output = responseJson["data"]["attributes"]["mal_eval_result"] if mal_eval_output: if mal_eval_output["label"]: mal_eval_label = mal_eval_output["label"] md += f"Mal-Eval Label: {mal_eval_label}\n" if mal_eval_output["probability_bucket"]: mal_eval_prob = mal_eval_output["probability_bucket"] md += f"Mal-Eval Malicious Likelihood: {mal_eval_prob}\n" results = CommandResults( readable_output=md, outputs_prefix="Inception.File_Details", outputs=responseJson, ) return results except DemistoException as err: # API will return 404 if the file is not found if "404" in str(err): results = CommandResults(readable_output="File not found: " + file_hash) return results else: raise err def variant_discovery_command(client, file_hash): try: response = client.get_file_reputation(file_hash) response = json.dumps(response) if "similarity" in response: response_json = json.loads(response) md_string = tableToMarkdown("File Variants Discovered", response_json["variants"]) results = CommandResults( outputs_prefix="Inception.Variants", readable_output=md_string, outputs=response_json, ) return results elif "variants" in response: results = CommandResults(readable_output="No variants discovered for: " + file_hash) return results except DemistoException as err: # API will return 500 if the file is not found if "500" in str(err): results = CommandResults(readable_output="File not found: " + file_hash) return results else: raise err def main() -> None: # pragma: no cover params = demisto.params() args = demisto.args() command = demisto.command() api_key = params.get("apikey", {}).get("password") # Params enabled by XSOAR functionality verify_certificate = not params.get("insecure", False) proxy = params.get("proxy", False) demisto.debug(f"Command being called is {command}") try: # Built-in command if command == "test-module": # This is the call made when clicking the integration Test button. client = Client( base_url="https://reputation.app.stairwell.com/api/v3/files/", verify=verify_certificate, headers={"X-Apikey": api_key}, proxy=proxy, ) result = test_module(client) return_results(result) elif command == "inception-file-enrichment": client = Client( base_url="https://reputation.app.stairwell.com/api/v3/files/", verify=verify_certificate, headers={"X-Apikey": api_key}, proxy=proxy, ) result = file_enrichment_command(client, args.get("fileHash")) return_results(result) elif command == "inception-variant-discovery": client = Client( base_url="https://app.stairwell.com/v202112/variants/", verify=verify_certificate, headers={"Authorization": api_key}, proxy=proxy, timeout=120, ) result = variant_discovery_command(client, args.get("sha256")) return_results(result) else: raise NotImplementedError(f"command {command} is not implemented.") # Log exceptions and return errors except Exception as e: demisto.error(traceback.format_exc()) # print the traceback return_error("\n".join(("Failed to execute {command} command.", "Error:", str(e)))) if __name__ in ("__main__", "__builtin__", "builtins"): main()