SearchIndicatorRelationships
This automation outputs the indicator relationships to context according to the provided query, using the entities, entityTypes, and relationships arguments. All arguments will use the AND operator. For example, using the following arguments entities=8.8.8.8 entities_types=Domain will provide only relationships that the 8.8.8.8 indicator has with indicators of type domain.
python · Base
Source
import re import demistomock as demisto from CommonServerPython import * from CommonServerUserPython import * # --------------------------------------------------- Helper functions--------------------------------------------- def to_context(relationshipsData: dict, verbose: bool) -> dict: """ Create context entries from the relationships returned from the searchRelationships command. :type relationships: ``list`` :param relationships: list of dict of relationships from the searchRelationships command. :type verbose: ``bool`` :param verbose: True if extended context should return, False for basic. :return: list of context for each relationship. :rtype: ``list`` """ demisto.debug(f"{relationshipsData=}") searchAfter = relationshipsData.get("SearchAfter", None) relationships = relationshipsData.get("data", []) or [] context_dict: dict = { "Relationships": [], "RelationshipsPagination": [], } for relationship in relationships: relationships_context = { "EntityA": relationship["entityA"], "EntityAType": relationship["entityAType"], "EntityB": relationship["entityB"], "EntityBType": relationship["entityBType"], "Relationship": relationship["name"], "Reverse": relationship["reverseName"], "ID": relationship["id"], } if verbose: relationships_context["Type"] = relationship.get("type", "") sources = relationship.get("sources") if sources: relationships_context["Reliability"] = sources[0].get("reliability", "") relationships_context["Brand"] = sources[0].get("brand", "") custom_fields = relationship.get("CustomFields", {}) if custom_fields: relationships_context["Revoked"] = custom_fields.get("revoked", "") relationships_context["FirstSeenBySource"] = custom_fields.get("firstseenbysource", "") relationships_context["LastSeenBySource"] = custom_fields.get("lastseenbysource", "") relationships_context["Description"] = custom_fields.get("description", "") context_dict["Relationships"].append(relationships_context) context_dict["RelationshipsPagination"].append(searchAfter) if searchAfter else [] return context_dict def handle_stix_types(entities_types: str) -> str: entities_types = argToList(entities_types) for e_type in entities_types: FeedIndicatorType.indicator_type_by_server_version(e_type) return ",".join(str(x) for x in entities_types).replace(", ", ",") def search_relationships_fromversion_6_6_0(args: dict) -> dict: for list_arg in ["entities", "entityTypes", "relationshipNames"]: args[list_arg] = argToList(args[list_arg]) if args[list_arg] else None res = demisto.searchRelationships(args) return res def search_relationships_toversion_6_5_0(args: dict) -> dict: res = demisto.executeCommand("searchRelationships", args) if is_error(res[0]): raise Exception("Error in searchRelationships command - {}".format(res[0]["Contents"])) return res[0].get("Contents", {}) def search_relationships( entities: Optional[str] = None, entities_types: Optional[str] = None, relationships: Optional[str] = None, limit: Optional[int] = None, query: Optional[str] = None, searchAfter: Optional[List[str]] = None, ) -> dict: args = { "entities": entities, "entityTypes": entities_types, "relationshipNames": relationships, "size": limit, "query": query, "searchAfter": searchAfter, } if is_demisto_version_ge("6.6.0"): return search_relationships_fromversion_6_6_0(args) return search_relationships_toversion_6_5_0(args) """ MAIN FUNCTION """ def main(): # pragma: no cover try: args = demisto.args() entities = args.get("entities", "") entities_types = args.get("entities_types", "") relationships = args.get("relationships", "") limit = int(args.get("limit", "20")) verbose = argToBoolean(args.get("verbose", "false")) revoked = argToBoolean(args.get("revoked", "false")) query = "revoked:T" if revoked else "revoked:F" searchAfter = argToList(args.get("searchAfter", "")) handle_stix_types(entities_types) if relationship_search_results := search_relationships( entities, entities_types, relationships, limit, query, searchAfter ): context = to_context(relationship_search_results, verbose) else: context = {} hr = tableToMarkdown( "Relationships", context.get("Relationships", []), headers=["EntityA", "EntityAType", "EntityB", "EntityBType", "Relationship"], headerTransform=lambda header: re.sub(r"\B([A-Z])", r" \1", header), ) return_results( CommandResults( readable_output=hr, outputs=context, outputs_key_field="ID", ) ) except Exception as e: return_error(f"Failed to execute SearchIndicatorRelationships automation. Error: {e!s}") """ ENTRY POINT """ if __name__ in ("__main__", "__builtin__", "builtins"): main()
README
This automation outputs the indicator relationships to context according to the provided query, using the entities, entityTypes, and relationships arguments. All arguments will use the AND operator. For example, using the following arguments entities=8.8.8.8 entities_types=Domain will provide only relationships that the 8.8.8.8 indicator has with indicators of type domain.
Script Data
| Name | Description |
|---|---|
| Script Type | python3 |
| Tags | basescript |
| Cortex XSOAR Version | 6.2.0 |
Inputs
| Argument Name | Description |
|---|---|
| entities | A comma-separated list of entities for which to search for relationships. For example: 192.168.1.1,192.168.1.2. The search applies to both entity A or entity B values. This argument can be used in conjunction with the entityType and the relationship arguments and all arguments will be treated with the AND operator. |
| entities_types | A comma-separated list of entity types for which to search for relationships. For example: IP,URL. This argument can be used in conjunction with the entities and the relationship arguments and all arguments will be treated with the AND operator. |
| relationships | A comma-separated list of relationship types for which to search for relationships. For example: related-to,contains. This argument can be used in conjunction with the entities and the entitiesTypes arguments and all arguments will be treated with the AND operator. |
| limit | The number of results to return. Default is 20. |
| verbose | Whether all of the relationships attributes will be returned or just the basic attributes. Default is false and the returned values will be name, entity A value, entity A type, entity B value, entity B type, relationships type. If true, all attributes will be returned. |
| revoked | The status of the relationships to return. Default is false. |
| searchAfter | Use the searchAfter token from the preceding response to indicate the starting point for retrieving the subsequent batch of relationships. |
Outputs
| Path | Description | Type |
|---|---|---|
| Relationships.EntityA | The source of the relationship. | String |
| Relationships.EntityB | The destination of the relationship. | string |
| Relationships.Relationship | The name of the relationship. | string |
| Relationships.Reverse | The name of the reverse relationship. | string |
| Relationships.EntityAType | The type of the source of the relationship. | string |
| Relationships.EntityBType | The type of the destination of the relationship. | string |
| Relationships.ID | The ID of the relationship. | string |
| Relationships.Reliability | The reliability of the relationship. | string |
| Relationships.Brand | The brand of the relationship. | string |
| Relationships.Revoked | True if the relationship is revoked. | string |
| Relationships.FirstSeenBySource | The first time seen by the source of the relationship. | string |
| Relationships.LastSeenBySource | The last time seen by the source of the relationship. | string |
| Relationships.Description | The description of the relationship. | string |
| Relationships.Type | The type of the relationship. | string |
| RelationshipsPagination | The searchAfter token for retrieving the next batch of relationships. | string |
Script Examples
Example command
!SearchIndicatorRelationships entities=google.com entities_types=IP
Context Example
{
"Relationships": [
{
"EntityA": "4.4.4.4",
"EntityAType": "IP",
"EntityB": "google.com",
"EntityBType": "Domain",
"ID": "31",
"Relationship": "related-to",
"Reverse": "related-to"
},
{
"EntityA": "8.8.8.8",
"EntityAType": "IP",
"EntityB": "google.com",
"EntityBType": "Domain",
"ID": "30",
"Relationship": "related-to",
"Reverse": "related-to"
}
],
"RelationshipsPagination": [
[
"1766338283557",
"8f8a88336e02a52ef31b3827b3b25d85"
]
]
}
Human Readable Output
Relationships
Entity A Entity A Type Entity B Entity B Type Relationship 4.4.4.4 IP google.com Domain related-to 8.8.8.8 IP google.com Domain related-to