Luminar_IOCs_and_leaked_credentials
This connector allows integration of intelligence-based IOC data and customer-related leaked records identified by Luminar.
Data Enrichment & Threat Intelligence · Luminar IOCs & leaked credentials · Feed
Details
| ID | Luminar_IOCs_and_leaked_credentials |
|---|---|
| Provider | Cognyte |
| Category | Data Enrichment & Threat Intelligence |
| From Version | 6.0.0 |
| Docker Image | demisto/python3:3.12.13.10116658 |
| Supported Modules | Agentix XSIAM |
README
Cognyte is a global leader in security analytics software that empowers governments and enterprises with Actionable
Intelligence for a safer world. Our open software fuses, analyzes and visualizes disparate data sets at scale to help
security organizations find the needles in the haystacks. Over 1,000 government and enterprise customers in more than
100 countries rely on Cognyte’s solutions to accelerate security investigations and connect the dots to successfully
identify, neutralize, and prevent threats to national security, business continuity and cyber security.
Luminar is an asset-based cybersecurity intelligence platform that empowers enterprise organizations to build and
maintain a proactive threat intelligence operation that enables to anticipate and mitigate cyber threats, reduce risk
and enhance security resilience. Luminar enables security teams to define a customized, dynamic monitoring plan to
uncover malicious activity in its earliest stages on all layers of the Web.
This connector allows integration of intelligence-based IOC data and customer-related leaked records identified by Luminar.
Configure Luminar IOCs & leaked credentials in Cortex
| Parameter | Description | Required |
|---|---|---|
| Luminar Base URL | Luminar Base URL | True |
| Luminar API Account ID | Luminar API Account ID | True |
| Luminar API Client ID | Luminar API Client ID | True |
| Luminar API Client Secret | Luminar API Secret | True |
| Trust any certificate (not secure) | Trust any certificate (not secure) | False |
| Use system proxy settings | Use system proxy settings | False |
| Fetch indicators | Fetch indicators | False |
| Indicator Reputation | Indicators from this integration instance will be marked with this reputation. | False |
| Source Reliability | Reliability of the source providing the intelligence data. | True |
| Feed Expiration Policy | Feed Expiration Policy | False |
| Feed Fetch Interval | Feed Fetch Interval | False |
| Tags | Supports CSV values. | False |
| Traffic Light Protocol Color | The Traffic Light Protocol (TLP) designation to apply to indicators fetched from the feed | False |
| Bypass exclusion list | When selected, the exclusion list is ignored for indicators from this feed. This means that if an indicator from this feed is on the exclusion list, the indicator might still be added to the system. | 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.
luminar-get-indicators
Gets Luminar Indicators
Base Command
luminar-get-indicators
Input
| Argument Name | Description | Required |
|---|---|---|
| limit | The maximum number of indicators to return. Default is 50. | Optional |
Context Output
There is no context output for this command.
Command example
!luminar-get-indicators limit="3"
Context Example
{
"Luminar": {
"Indicators": [
{
"Indicator Type": "File",
"Indicator Value": "a35866ff36a7ec0a226b8f814f3642185742020e",
"Malware Family": "SlayerRAT v0.4",
"rawJSON": {
"created": "2016-02-15T00:00:00.000Z",
"created_by_ref": "identity--cd3843c0-8119-4ac0-9409-cec757123a6a",
"id": "indicator--88369314-3515-4c5c-a3e3-dba75e4ae964",
"indicator_types": [
"malicious-activity"
],
"modified": "2016-02-15T00:00:00.000Z",
"name": "SlayerRAT v0.4",
"pattern": "[file:hashes.'SHA-1' = 'a35866ff36a7ec0a226b8f814f3642185742020e']",
"pattern_type": "stix",
"spec_version": "2.1",
"type": "indicator",
"valid_from": "2016-02-15T00:00:00.000Z"
}
},
{
"Indicator Type": "Domain",
"Indicator Value": "xbodyyellow.top",
"Malware Family": "Locky",
"rawJSON": {
"created": "2016-02-22T00:00:00.000Z",
"created_by_ref": "identity--cd3843c0-8119-4ac0-9409-cec757123a6a",
"id": "indicator--0240fda0-1b77-4bde-86d8-eeb27203e4d7",
"indicator_types": [
"malicious-activity"
],
"modified": "2016-02-22T00:00:00.000Z",
"name": "Locky",
"pattern": "[domain-name:value = 'xbodyyellow.top']",
"pattern_type": "stix",
"spec_version": "2.1",
"type": "indicator",
"valid_from": "2016-02-22T00:00:00.000Z"
}
},
{
"Indicator Type": "Email",
"Indicator Value": "javamaker@inbox.ru",
"Malware Family": "OilRig",
"rawJSON": {
"created": "2016-10-10T00:00:00.000Z",
"created_by_ref": "identity--cd3843c0-8119-4ac0-9409-cec757123a6a",
"id": "indicator--a1ee47e7-fe49-4fae-8c20-7a14452c5da7",
"indicator_types": [
"malicious-activity"
],
"modified": "2016-10-10T00:00:00.000Z",
"name": "OilRig",
"pattern": "[email-addr:value = 'javamaker@inbox.ru']",
"pattern_type": "stix",
"spec_version": "2.1",
"type": "indicator",
"valid_from": "2016-10-10T00:00:00.000Z"
}
}
]
}
}
Human Readable Output
Indicators from Luminar
Indicator Type Indicator Value Malware Family File a35866ff36a7ec0a226b8f814f3642185742020e SlayerRAT v0.4 Domain xbodyyellow.top Locky javamaker@inbox.ru OilRig
luminar-get-leaked-records
Gets Luminar Leaked Records
Base Command
luminar-get-leaked-records
Input
| Argument Name | Description | Required |
|---|---|---|
| limit | The maximum number of leaked records to return. Default is 50. | Optional |
Context Output
There is no context output for this command.
Command example
!luminar-get-leaked-records limit="3"
Context Example
{
"Luminar": {
"Leaked_Credentials": [
{
"Credentials": "######",
"Indicator Type": "Account",
"Indicator Value": "a@a.com",
"rawJSON": {
"account_login": "a@a.com",
"credential": "######",
"display_name": "a@a.com",
"id": "user-account--e4af982e-4673-4795-94d6-17b5ef96f8ae",
"spec_version": "2.1",
"type": "user-account"
}
},
{
"Credentials": "######",
"Indicator Type": "Account",
"Indicator Value": "b@b.com",
"rawJSON": {
"account_login": "b@b.com",
"credential": "######",
"display_name": "b@b.com",
"id": "user-account--b8fc71bf-3542-4fcb-a0c7-70dc5e7366e8",
"spec_version": "2.1",
"type": "user-account"
}
},
{
"Credentials": "######",
"Indicator Type": "Account",
"Indicator Value": "c@c.com",
"rawJSON": {
"account_login": "c@c.com",
"credential": "######",
"display_name": "c@c.com",
"id": "user-account--885ee892-320c-4e62-8161-a999d2df086a",
"spec_version": "2.1",
"type": "user-account"
}
}
]
}
}
Human Readable Output
Leaked Credentials from Luminar
Indicator Type Indicator Value Credentials Account a@a.com ###### Account b@b.com ###### Account c@c.com ######
luminar-reset-fetch-indicators
WARNING: This command will reset your fetch history.
Base Command
luminar-reset-fetch-indicators
Input
There are no input arguments for this command.
Context Output
There is no context output for this command.
Command example
!luminar-reset-fetch-indicators
Human Readable Output
Fetch history deleted successfully
Configuration parameters
luminar_base_url— Luminar Base URL (required)luminar_account_id— Luminar API Account ID (required)luminar_client_id— Luminar API Client ID (required)luminar_client_secret— Luminar API Client Secret (required)insecure— Trust any certificate (not secure)proxy— Use system proxy settingsfeed— Fetch indicatorsfeedReputation— Indicator ReputationfeedReliability— Source Reliability (required)feedExpirationPolicy—feedExpirationInterval—feedFetchInterval— Feed Fetch IntervalfeedTags— Tagstlp_color— Traffic Light Protocol ColorfeedBypassExclusionList— Bypass exclusion listfeedIncremental— Incremental Feed
Commands (3)
-
luminar-get-indicatorsGets Luminar Indicators
-
luminar-get-leaked-recordsGets Luminar Leaked Records
-
luminar-reset-fetch-indicatorsThis command will reset your fetch history.
from functools import partial from urllib import parse from CommonServerPython import * stix_regex_parser = re.compile(r"([\w-]+?):(\w.+?) (?:[!><]?=|IN|MATCHES|LIKE) '(.*?)' *[OR|AND|FOLLOWEDBY]?") API_URL = "/externalApi" LEAKED_RECORD = "LEAKED CREDENTIAL" LEAKED_CREDENTIALS_TABLE_HEADER = "Leaked Credentials from Luminar" IOC_TABLE_HEADER = "Indicators from Luminar" LUMINAR_TO_XSOAR_TYPES = { "file": FeedIndicatorType.File, "ipv4-addr": FeedIndicatorType.IP, "ipv6-addr": FeedIndicatorType.IP, "mac-addr": FeedIndicatorType.IP, "domain-name": FeedIndicatorType.Domain, "email-addr": FeedIndicatorType.Email, "url": FeedIndicatorType.URL, "windows-registry-key": FeedIndicatorType.Registry, "user-account": FeedIndicatorType.Account, } def enrich_incident_items(parent, childrens, feed_tags, tlp_color): """ This will get Account, Incident objects Args: parent: Incident childrens: Accounts feed_tags: feed_tags tlp_color: tlp_color Returns: Incident, Account objects """ modified_childrens = [] for children in childrens: tags = [LEAKED_RECORD, f'Incident: {parent.get("name")}', f'Credentials:{children.get("credential")}'] if feed_tags: tags.extend(list(feed_tags)) additional_field = { "tags": tags, "category": LEAKED_RECORD, "accounttype": LEAKED_RECORD, "displayname": children.get("display_name"), "emailaddress": children.get("display_name"), "creationdate": parent.get("created"), "firstseenbysource": parent.get("created"), "updateddate": parent.get("modified"), "lastseenbysource": parent.get("created"), "shortdescription": parent.get("description") or "", "trafficlightprotocol": tlp_color, } indicator = { "value": children.get("account_login"), "occurred": datetime.strptime(parent.get("created"), "%Y-%m-%dT%H:%M:%S.%f%z").strftime("%m/%d/%Y, %H:%M:%S"), "type": FeedIndicatorType.Account, "rawJSON": dict(children), "fields": additional_field, } modified_childrens.append(indicator) return parent, modified_childrens def enrich_malware_items(parent, childrens, feed_tags, tlp_color): """ This will get Malware, Indicator objects Args: parent: Malware childrens: Indicator feed_tags: feed_tags tlp_color: tlp_color Returns: Malware, Indicator Objects """ modified_childrens = [] modified_parent = None all_tags = set() for children in childrens: indicator_type = None pattern = children.get("pattern") for match in stix_regex_parser.findall(pattern): stix_type, stix_property, value = match if stix_type in LUMINAR_TO_XSOAR_TYPES: indicator_type = LUMINAR_TO_XSOAR_TYPES[stix_type] if indicator_type == FeedIndicatorType.File and not str(stix_property).__contains__("hashes"): indicator_type = None else: indicator_type = stix_type if indicator_type: malware_types = parent.get("malwareTypes") children.update(indicator_type=indicator_type) parent["name"] = children["name"] children["value"] = value relationship_obj = EntityRelationship( name=EntityRelationship.Relationships.INDICATED_BY, entity_a=value, entity_a_type=indicator_type, entity_b=parent["name"], entity_b_type=ThreatIntel.ObjectsNames.MALWARE, ) tags = list(children["indicator_types"]) all_tags.update(tags) tags.append("Malware Family: " + parent["name"]) malware_types_str = ",".join(malware_types) indicator_type_str = ",".join(children["indicator_types"]) tags.append(f"Malware Type: {malware_types_str}") if feed_tags: tags.extend(list(feed_tags)) indicator = { "value": value, "occurred": datetime.strptime(children["created"], "%Y-%m-%dT%H:%M:%S.%f%z").strftime("%m/%d/%Y, %H:%M:%S"), "type": indicator_type, "rawJSON": dict(children), "fields": { "category": "Malware", "malwarefamily": children["name"], "shortdescription": f"This {indicator_type} was involved in {indicator_type_str}", "creationdate": children["created"], "firstseenbysource": children["created"], "updateddate": children["modified"], "lastseenbysource": children["modified"], "tags": tags, "trafficlightprotocol": tlp_color, }, "relationships": [relationship_obj.to_indicator()], } modified_childrens.append(indicator) if parent: additional_fields = { "STIX Is Malware Family": parent["is_family"], "tags": list(all_tags), "stixid": parent["id"], "STIX Malware Types": parent["malwareTypes"], "malware_types": parent["malwareTypes"], } modified_parent = { "value": parent["name"], "occurred": datetime.strptime(parent["created"], "%Y-%m-%dT%H:%M:%S.%f%z").strftime("%m/%d/%Y, %H:%M:%S"), "type": ThreatIntel.ObjectsNames.MALWARE, "rawJSON": dict(parent), "fields": additional_fields, } return modified_parent, modified_childrens def generic_item_finder(all_objects, item_id): return filter(lambda x: x.get("id") == item_id, all_objects) class Client(BaseClient): """ This class handles logic for Luminar API """ def __init__( self, base_url: str, account_id: str, client_id: str, client_secret: str, verify: bool = False, proxy: bool = False, tags: list = [], tlp_color: Optional[str] = None, ): BaseClient.__init__( self, base_url, verify=verify, proxy=proxy, ok_codes=(200,), ) self.luminar_account_id = account_id self.luminar_client_id = client_id self.luminar_client_secret = client_secret self.offset = 0 self.limit = 100 self.feed_tags = tags self.tlp_color = tlp_color def fetch_access_token(self): """ function to fetch the access token """ req_url = f"{self._base_url}/realm/{self.luminar_account_id}/token" req_headers = {"Content-Type": "application/x-www-form-urlencoded;charset=utf-8"} req_data = parse.urlencode( {"grant_type": "client_credentials", "client_id": self.luminar_client_id, "client_secret": self.luminar_client_secret} ) r = requests.post(req_url, headers=req_headers, data=req_data) return r.json()["access_token"] def fetch_luminar_api_feeds(self, is_fetch_command=True): """ This will fetch the luminar feed for FEED Command Returns: """ is_feed = True while is_feed: access_token = self.fetch_access_token() params: Dict[str, Union[int, int]] = {} if is_fetch_command: last_run = self.get_last_run() if last_run: params = {"timestamp": int(last_run), "limit": self.limit} else: params = {"limit": self.limit, "offset": self.offset} self.offset += self.limit else: params = {"limit": self.limit, "offset": self.offset} self.offset += self.limit req_url = f"{self._base_url}/stix" req_headers = {"Authorization": f"Bearer {access_token}"} luminar_feed = requests.get(req_url, params=params, headers=req_headers).json() luminar_objects = luminar_feed.get("objects") if not luminar_objects or len(luminar_objects) == 1: if is_fetch_command: self.set_last_run() is_feed = False yield luminar_objects def fetch_luminar_indicators(self): """ This method will create indicators into XSOAR """ for luminar_feed in self.fetch_luminar_api_feeds(is_fetch_command=True): if not luminar_feed: continue get_item_by_id = partial(generic_item_finder, luminar_feed) relationships: Dict[Any, Any] = {} for relationship in filter(lambda x: x.get("type") == "relationship", luminar_feed): relationship_items = relationships.get(relationship.get("target_ref"), []) relationship_items.append(relationship.get("source_ref")) relationships[relationship["target_ref"]] = relationship_items for key, group in relationships.items(): parent = next(get_item_by_id(key), None) children: List[Any] = list(filter(None, [next(get_item_by_id(item_id), None) for item_id in group])) if parent and parent.get("type") == "malware": indicators_list = [] modified_parent, modified_childrens = enrich_malware_items(parent, children, self.feed_tags, self.tlp_color) indicators_list.extend(modified_childrens) indicators_list.append(modified_parent) for b in batch(indicators_list, batch_size=2000): demisto.createIndicators(b) elif parent and parent.get("type") == "incident": incidents_list = [] modified_parent, modified_childrens = enrich_incident_items(parent, children, self.feed_tags, self.tlp_color) incidents_list.extend(modified_childrens) incidents_list.append(modified_parent) for b in batch(incidents_list, batch_size=2000): demisto.createIndicators(b) else: parent_type = parent.get("type") if parent else "" demisto.info(f"Type not handled : {parent_type}") continue def get_luminar_indicators_list(self): """ This will get the indicators from Luminar for get-indicators method. Returns: list """ luminar_indicators_list = [] for luminar_feed in self.fetch_luminar_api_feeds(is_fetch_command=False): luminar_indicators = [] if not luminar_feed: continue if luminar_feed: ioc_list = [ele for ele in list(luminar_feed) if ele["type"] == "indicator"] if ioc_list: luminar_indicators.append(ioc_list) if luminar_indicators: for lum_indicator in luminar_indicators[0]: indicator_type = None pattern = lum_indicator["pattern"] for match in stix_regex_parser.findall(pattern): stix_type, stix_property, value = match if stix_type in LUMINAR_TO_XSOAR_TYPES: indicator_type = LUMINAR_TO_XSOAR_TYPES[stix_type] if indicator_type == FeedIndicatorType.File and not str(stix_property).__contains__("hashes"): indicator_type = None if indicator_type: indicator = { "Indicator Type": indicator_type, "Indicator Value": value, "Malware Family": lum_indicator["name"], "rawJSON": dict(lum_indicator), } else: indicator = {} demisto.debug(f"{indicator_type=} -> {indicator=}") luminar_indicators_list.append(indicator) return luminar_indicators_list def get_luminar_leaked_credentials_list(self): """ This will get the leaked records from Luminar for get-leaked-records method. Returns: list """ luminar_leaked_credentials_list = [] for luminar_feed in self.fetch_luminar_api_feeds(is_fetch_command=False): luminar_leaked_records = [] if not luminar_feed: continue if luminar_feed: user_account_list = [ele for ele in list(luminar_feed) if ele["type"] == "user-account"] if user_account_list: luminar_leaked_records.append(user_account_list) if luminar_leaked_records: for luminar_leaked_record in luminar_leaked_records[0]: credentials = luminar_leaked_record.get("credential", "") indicator = { "Indicator Type": FeedIndicatorType.Account, "Indicator Value": luminar_leaked_record["account_login"], "Credentials": credentials, "rawJSON": dict(luminar_leaked_record), } luminar_leaked_credentials_list.append(indicator) return luminar_leaked_credentials_list @staticmethod def set_last_run(): """ sets the last run """ current_time = datetime.now() current_timestamp = datetime.timestamp(current_time) timestamp = str(int(current_timestamp)) demisto.setIntegrationContext({"last_modified_time": timestamp}) demisto.info(f"set last_run: {timestamp}") @staticmethod def get_last_run() -> str: """Gets last run time in timestamp Returns: last run in timestamp, or '' if no last run """ return demisto.getIntegrationContext().get("last_modified_time") def cognyte_luminar_get_leaked_records(client: Client, args: dict): """ This function is used to fetch the luminar indicators and show in the war room Args: client: client object args: limit Returns: """ limit = arg_to_number(args.get("limit", 50), arg_name="limit") leaked_records = client.get_luminar_leaked_credentials_list() leaked_records = leaked_records[:limit] if leaked_records: readable_output = tableToMarkdown( name=LEAKED_CREDENTIALS_TABLE_HEADER, t=leaked_records, headers=["Indicator Type", "Indicator Value", "Credentials"], headerTransform=pascalToSpace, ) return CommandResults( outputs=leaked_records, outputs_prefix="Luminar.Leaked_Credentials", outputs_key_field="", readable_output=readable_output, raw_response=leaked_records, ) else: return CommandResults(readable_output="No Leaked Records Found.") def cognyte_luminar_get_indicators(client: Client, args: dict): """ This function is used to fetch the luminar indicators and show in the war room Args: client: client object args: limit Returns: """ limit = arg_to_number(args.get("limit", 50), arg_name="limit") indicators_list = client.get_luminar_indicators_list() indicators_list = indicators_list[:limit] if indicators_list: readable_output = tableToMarkdown( name=IOC_TABLE_HEADER, t=indicators_list, headers=["Indicator Type", "Indicator Value", "Malware Family"], headerTransform=pascalToSpace, ) return CommandResults( outputs=indicators_list, outputs_prefix="Luminar.Indicators", outputs_key_field="", readable_output=readable_output, raw_response=indicators_list, ) else: return CommandResults(readable_output="No Indicators Found.") def module_test(client: Client) -> str: try: client.fetch_access_token() except Exception: raise Exception("Could not connect to Luminar API\n\nCheck your credentials and try again.") return "ok" def reset_last_run(): """ Reset the last run from the integration context """ demisto.setIntegrationContext({}) return CommandResults(readable_output="Fetch history deleted successfully") def fetch_indicators_command(client: Client): """fetch indicators from the Luminar API Args: client: Client object Returns: list of indicators(list) """ client.fetch_luminar_indicators() return True def main() -> None: params = demisto.params() base_url = urljoin(params.get("luminar_base_url"), API_URL) account_id = params.get("luminar_account_id") client_id = params.get("luminar_client_id") client_secret = params.get("luminar_client_secret") verify_certificate = not params.get("insecure", False) proxy = params.get("proxy", False) tags = argToList(params.get("feedTags")) tlp_color = params.get("tlp_color") client = Client( base_url=base_url, account_id=account_id, client_id=client_id, client_secret=client_secret, verify=verify_certificate, proxy=proxy, tags=tags, tlp_color=tlp_color, ) command = demisto.command() demisto.info(f"Command being called is {demisto.command()}") try: if command == "fetch-indicators": fetch_indicators_command(client=client) elif command == "luminar-get-indicators": return_results(cognyte_luminar_get_indicators(client=client, args=demisto.args())) elif command == "luminar-get-leaked-records": return_results(cognyte_luminar_get_leaked_records(client=client, args=demisto.args())) elif command == "luminar-reset-fetch-indicators": return_results(reset_last_run()) elif command == "test-module": result = module_test(client=client) return_results(result) except Exception as e: demisto.error(traceback.format_exc()) # print the traceback return_error(f"Failed to execute {demisto.command()} command.\nError:\n{e!s}") if __name__ in ("__builtin__", "builtins", "__main__"): main()