SOCRadarIoCEnrichment
Enrich indicators with deep threat intelligence using SOCRadar IoC Enrichment API. Get categorization, signal strength, confidence levels, and historical data.
Data Enrichment & Threat Intelligence · SOCRadar
Details
| ID | SOCRadarIoCEnrichment |
|---|---|
| Provider | SOCRadar |
| Category | Data Enrichment & Threat Intelligence |
| From Version | 6.10.0 |
| Docker Image | demisto/python3:3.12.13.10116658 |
| Supported Modules | Agentix XSIAM |
README
SOCRadar IoC Enrichment Integration
Overview
The SOCRadar IoC Enrichment integration provides deep threat intelligence enrichment for indicators of compromise (IoCs). Get comprehensive data including categorization, signal strength, confidence levels, historical events, threat actor attribution, and campaign associations.
Key Features
- Rich Threat Context: Detailed categorization (CDN, Cloud, Malware, ThreatActor, Tor, VPN, etc.)
- Signal Strength: IoC reliability assessment (Very Strong to Noisy)
- Confidence Levels: Cross-source validation (Very High, High, Medium, Low)
- Historical Data: Timeline of indicator activity across threat feeds
- Threat Attribution: Associated campaigns, threat actors, malware families
- Target Intelligence: Industries and countries targeted
- Performance Optimized: AI insights excluded for fast responses
Configuration
Prerequisites
- SOCRadar API Key with IoC Enrichment access
- Network access to
platform.socradar.com
Setup
- Navigate to Settings → Integrations → Servers & Services
- Search for “SOCRadar IoC Enrichment”
- Click Add Instance
- Configure:
- Name: Instance name
- API Key: Your SOCRadar API key
- Source Reliability: B - Usually reliable (recommended)
- Click Test to validate
- Click Save & Exit
Commands
ip
Enriches IP addresses with threat intelligence data.
Input
| Argument | Description | Required |
|---|---|---|
| ip | IP addresses to enrich (IPv4 or IPv6). Supports multiple IPs (comma-separated). | Required |
Context Output
| Path | Type | Description |
|---|---|---|
| SOCRadarIoCEnrichment.IP.Indicator | String | The IP address |
| SOCRadarIoCEnrichment.IP.Score | Number | Threat score (0-100) |
| SOCRadarIoCEnrichment.IP.SignalStrength | String | IoC reliability (Very Strong, Strong, Moderate, Slightly Noisy, Noisy) |
| SOCRadarIoCEnrichment.IP.Confidence | String | Cross-source confidence (Very High, High, Medium, Low) |
| SOCRadarIoCEnrichment.IP.Country | String | Country of origin |
| SOCRadarIoCEnrichment.IP.ASN | String | Autonomous System Name |
| SOCRadarIoCEnrichment.IP.FirstSeen | Date | First observed date |
| SOCRadarIoCEnrichment.IP.LastSeen | Date | Last observed date |
| SOCRadarIoCEnrichment.IP.Categorization | Object | Service categorization flags |
| SOCRadarIoCEnrichment.IP.Categorization.Malware | Boolean | Associated with malware |
| SOCRadarIoCEnrichment.IP.Categorization.ThreatActor | Boolean | Associated with threat actors |
| SOCRadarIoCEnrichment.IP.Categorization.Tor | Boolean | Tor exit node |
| SOCRadarIoCEnrichment.IP.Categorization.VPN | Boolean | VPN service |
| SOCRadarIoCEnrichment.IP.Categorization.CDN | Boolean | Content delivery network |
| SOCRadarIoCEnrichment.IP.Categorization.Cloud | Boolean | Cloud hosting |
| SOCRadarIoCEnrichment.IP.Classifications | Object | Threat classifications |
| SOCRadarIoCEnrichment.IP.Classifications.Campaign | String | Associated campaign name |
| SOCRadarIoCEnrichment.IP.Classifications.Malwares | Array | Associated malware families |
| SOCRadarIoCEnrichment.IP.Classifications.ThreatActors | Array | Associated threat actors |
| SOCRadarIoCEnrichment.IP.Classifications.Industries | Array | Targeted industries |
| SOCRadarIoCEnrichment.IP.Classifications.TargetCountries | Array | Targeted countries |
| SOCRadarIoCEnrichment.IP.History | Array | Historical events (last 10) |
| DBotScore.Score | Number | DBot score (0=Unknown, 1=Good, 2=Suspicious, 3=Malicious) |
Command Example
!ip ip="104.251.122.20"
!ip ip="1.1.1.1,8.8.8.8"
domain
Enriches domains with threat intelligence data.
Input
| Argument | Description | Required |
|---|---|---|
| domain | Domain names to enrich. Supports multiple domains (comma-separated). | Required |
Context Output
Similar to IP command, with SOCRadarIoCEnrichment.Domain.* prefix.
Command Example
!domain domain="malicious-site.com"
!domain domain="example.com,test.net"
url
Enriches URLs with threat intelligence data.
Input
| Argument | Description | Required |
|---|---|---|
| url | URLs to enrich. Supports multiple URLs (comma-separated). | Required |
Context Output
Similar to IP command, with SOCRadarIoCEnrichment.URL.* prefix.
Command Example
!url url="https://malicious-site.com/payload.exe"
!url url="http://phishing.example.com,https://c2.attacker.net"
file
Enriches file hashes with threat intelligence data.
Input
| Argument | Description | Required |
|---|---|---|
| file | File hashes to enrich (MD5, SHA1, SHA256). Supports multiple hashes. | Required |
Context Output
Similar to IP command, with SOCRadarIoCEnrichment.File.* prefix.
Command Example
!file file="44d88612fea8a8f36de82e1278abb02f"
!file file="3b7b359ea17ac76341957573e332a2d6bcac363401ac71c8df94dac93df6d792"
DBot Score Interpretation
| DBot Score | Meaning | Criteria |
|---|---|---|
| 3 | Malicious | Score > 80 OR Signal Strength = Very Strong/Strong |
| 2 | Suspicious | Score 40-80 OR Signal Strength = Moderate |
| 1 | Good | Score 1-40 |
| 0 | Unknown | Score = 0 or NULL |
Use Cases
1. Incident Investigation
# Enrich suspicious IP from logs
!ip ip="192.168.1.100"
# Check associated domain
!domain domain="suspicious-domain.com"
# Investigate related hash
!file file="abc123def456..."
Output: Get complete threat context including campaigns, threat actors, target industries, and historical activity.
2. Threat Hunting
# Enrich multiple indicators
!ip ip="1.1.1.1,2.2.2.2,3.3.3.3"
Output: Batch enrichment with categorization flags to identify Tor nodes, VPNs, malware C2s, etc.
3. Playbook Enrichment
- id: "1"
task: Enrich Incident IOCs
command: ip
args:
ip: ${incident.sourceip}
- id: "2"
task: Check Signal Strength
condition: ${SOCRadarIoCEnrichment.IP.SignalStrength} == "Very Strong"
nexttasks:
"true":
- Block IP
4. Threat Intelligence Analysis
# Get detailed classification
!ip ip="203.0.113.45"
Output:
- Signal Strength: Very Strong
- Confidence: Very High
- Campaign: APT28 Infrastructure
- Threat Actors: [“APT28”, “Fancy Bear”]
- Target Industries: [“Government”, “Defense”]
- Malwares: [“CHOPSTICK”, “SOURFACE”]
Signal Strength Explained
| Level | Description | Recommended Action |
|---|---|---|
| Very Strong | High-confidence malicious indicator, low false positive rate | Block immediately |
| Strong | Reliable malicious indicator | Block with review |
| Moderate | Potentially malicious, moderate confidence | Monitor/investigate |
| Slightly Noisy | Some legitimate use cases exist | Investigate context |
| Noisy | High false positive rate | Review carefully before action |
Confidence Levels
| Level | Description |
|---|---|
| Very High | Validated across multiple high-quality sources |
| High | Confirmed by multiple sources |
| Medium | Moderate source validation |
| Low | Limited source validation |
Categorization Flags
| Flag | Meaning |
|---|---|
| Malware | Associated with malware distribution/C2 |
| ThreatActor | Attributed to known threat actor |
| Tor | Tor network node |
| VPN | VPN service endpoint |
| Proxy | Proxy service |
| CDN | Content delivery network |
| Cloud | Cloud hosting (AWS, Azure, GCP, etc.) |
| Hosting | Web hosting service |
| Honeypot | Honeypot/research environment |
| Cryptocurrency | Crypto mining/wallet |
| Scanner | Port/vulnerability scanner |
Performance Notes
- AI Insights Excluded: For optimal performance, AI-generated insights are not requested
- Fields Requested: indicator_details, indicator_history, indicator_relations
- Response Time: Typically < 2 seconds per indicator
- Rate Limits: Check your API key’s rate limit with SOCRadar
Troubleshooting
Test Module Fails
Error: “Authorization Error”
- Solution: Verify API key is correct and has IoC Enrichment access
Error: “Connection failed”
- Solution: Check network connectivity to platform.socradar.com
No Data Returned
Issue: Empty response for valid indicator
- Cause: Indicator not in SOCRadar database
- Note: No data doesn’t mean indicator is safe, just unknown to SOCRadar
Rate Limit Exceeded
Error: “Rate limit has been exceeded”
- Solution: Contact SOCRadar to increase rate limit or wait for reset
Best Practices
- Enrich All IOCs: Run enrichment on all indicators during investigation
- Trust Signal Strength: Use signal strength for automated blocking decisions
- Check Categorization: Validate if indicator is CDN/Cloud before blocking
- Review History: Examine historical events for pattern analysis
- Combine with Other Sources: Use alongside other TI feeds for validation
- Playbook Integration: Automate enrichment in incident response playbooks
Additional Resources
- API Documentation: https://platform.socradar.com/docs/api/
- Support: operation@socradar.io
- SOCRadar Platform: https://platform.socradar.com
Version History
- 1.0.0: Initial release with IP, Domain, URL, and File enrichment
Integration Type: Data Enrichment & Threat Intelligence
Vendor: SOCRadar
Support: Community
Categories: Threat Intelligence, IoC Enrichment, Reputation
Configuration parameters
apikey— (required)insecure— Trust any certificate (not secure)proxy— Use system proxy settingsintegrationReliability— Source Reliabilityinclude_ai_insights— Include AI Insights (slower response time)
Commands (5)
-
domainEnriches domains with SOCRadar IoC threat intelligence data.
-
fileEnriches file hashes with SOCRadar IoC threat intelligence data.
-
ipEnriches IP addresses with SOCRadar IoC threat intelligence data.
-
socradar-ioc-enrichmentGeneric enrichment command with automatic indicator type detection. Enriches any indicator type (IP, domain, URL, hash) without specifying the type.
-
urlEnriches URLs with SOCRadar IoC threat intelligence data.
import demistomock as demisto # noqa: F401 from CommonServerPython import * # noqa: F401 from CommonServerUserPython import * # noqa import urllib3 import traceback from typing import Any import re from json.decoder import JSONDecodeError # Disable insecure warnings urllib3.disable_warnings() # pylint: disable=no-member """ CONSTANTS """ SOCRADAR_API_ENDPOINT = "https://platform.socradar.com/api" MESSAGES: dict[str, str] = { "BAD_REQUEST_ERROR": "An error occurred while fetching the data.", "AUTHORIZATION_ERROR": "Authorization Error: make sure API Key is correctly set.", "RATE_LIMIT_EXCEED_ERROR": "Rate limit has been exceeded. Please check your API key's rate limit.", } INTEGRATION_NAME = "SOCRadar IoC Enrichment" # Fields to request (excluding AI insight for performance) DEFAULT_FIELDS = ["indicator_details", "indicator_history", "indicator_relations"] """ CLIENT CLASS """ class Client(BaseClient): """Client class to interact with the SOCRadar IoC Enrichment API""" def __init__(self, base_url, api_key, verify, proxy, include_ai_insights=False): super().__init__(base_url, verify=verify, proxy=proxy) self.api_key = api_key self.include_ai_insights = include_ai_insights def get_indicator_enrichment(self, indicator: str, fields: list[str] | None = None): """Get indicator enrichment from SOCRadar IoC Enrichment API Args: indicator: The indicator value (IP, domain, URL, or hash) fields: List of fields to include (defaults to all except AI insight) Returns: API response with enrichment data """ suffix = "/ioc_enrichment/get/indicator_details" if fields is None: if self.include_ai_insights: fields = DEFAULT_FIELDS + ["indicator_ai_insight"] else: fields = DEFAULT_FIELDS request_body = {"indicator": indicator, "fields": fields} headers = {"Api-Key": self.api_key, "Content-Type": "application/json"} response = self._http_request( method="POST", url_suffix=suffix, json_data=request_body, headers=headers, timeout=60, error_handler=self.handle_error_response, resp_type="json", ) return response def check_auth(self): """Check API authentication by making a test request""" try: demisto.debug("Testing API authentication...") # Use a well-known IP for testing response = self.get_indicator_enrichment("8.8.8.8") demisto.debug(f"Auth test response: {response}") return response except Exception as e: demisto.error(f"Authentication test failed: {str(e)}") raise DemistoException(f"Authentication failed: {str(e)}") @staticmethod def handle_error_response(response) -> None: """Handles API response errors""" error_reason = "" try: json_resp = response.json() error_reason = json_resp.get("error") or json_resp.get("message", "") except JSONDecodeError: pass status_code_messages = { 400: f"{MESSAGES['BAD_REQUEST_ERROR']} Reason: {error_reason}", 401: MESSAGES["AUTHORIZATION_ERROR"], 404: f"{MESSAGES['BAD_REQUEST_ERROR']} Reason: {error_reason}", 429: MESSAGES["RATE_LIMIT_EXCEED_ERROR"], } if response.status_code in status_code_messages: demisto.debug(f"Response Code: {response.status_code}, Reason: {status_code_messages[response.status_code]}") raise DemistoException(status_code_messages[response.status_code]) else: try: response.raise_for_status() except Exception as e: raise DemistoException(f"Error in API call [{response.status_code}] - {response.text}\n{e}") """ HELPER FUNCTIONS """ def calculate_dbot_score(score: float) -> int: """Calculate DBot score from SOCRadar enrichment data. SOCRadar score ranges: 0 → Unknown (0) 1–50 → Medium → Suspicious (2) 51–75 → High → Malicious (3) 76–100 → Critical → Malicious (3) Returns: DBot score (0=Unknown, 2=Suspicious, 3=Malicious) """ if isinstance(score, list): score = score[0] if score else 0 elif score is None: score = 0 try: score = float(score) except (ValueError, TypeError): score = 0 if score == 0: return 0 # Unknown elif score <= 50: return 2 # Medium → Suspicious else: return 3 # High / Critical → Malicious class Validator: @staticmethod def validate_domain(domain_to_validate): if not isinstance(domain_to_validate, str) or len(domain_to_validate) > 255: return False if domain_to_validate.endswith("."): domain_to_validate = domain_to_validate[:-1] domain_regex = re.compile(r"(?!-)[A-Z\d-]{1,63}(?<!-)$", re.IGNORECASE) return all(domain_regex.match(x) for x in domain_to_validate.split(".")) @staticmethod def validate_ipv4(ip_to_validate): return is_ip_valid(ip_to_validate) @staticmethod def validate_ipv6(ip_to_validate): return is_ipv6_valid(ip_to_validate) @staticmethod def validate_hash(hash_to_validate): return get_hash_type(hash_to_validate) != "Unknown" @staticmethod def validate_url(url_to_validate): """Validate URL format""" url_regex = re.compile( r"^https?://" r"(?:(?:[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?\.)+[A-Z]{2,6}\.?|" r"localhost|" r"\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})" r"(?::\d+)?" r"(?:/?|[/?]\S+)$", re.IGNORECASE, ) return url_regex.match(url_to_validate) is not None @staticmethod def raise_if_ip_not_valid(ip: str): if not Validator.validate_ipv4(ip) and not Validator.validate_ipv6(ip): raise ValueError(f'IP "{ip}" is not a valid IPv4 or IPv6 address') @staticmethod def raise_if_domain_not_valid(domain: str): if not Validator.validate_domain(domain): raise ValueError(f'Domain "{domain}" is not a valid domain address') @staticmethod def raise_if_hash_not_valid(file_hash: str): if not Validator.validate_hash(file_hash): raise ValueError(f'Hash "{file_hash}" is not a valid hash') @staticmethod def raise_if_url_not_valid(url: str): if not Validator.validate_url(url): raise ValueError(f'URL "{url}" is not a valid URL') def build_entry_context(raw_response: dict, indicator: str) -> dict: """Build context entry from API response""" # Extract main components details = raw_response.get("details", {}) summary = raw_response.get("summary", {}) categorization = raw_response.get("categorization", {}) classifications = raw_response.get("top_classifications", {}) # Changed to top_classifications history = raw_response.get("history", {}) activity_labels = raw_response.get("activity_label_dict", {}) premium_feeds = raw_response.get("premium_feeds", []) relations = raw_response.get("relations", []) # Extract score - API returns it as array, take first value and round to 2 decimals score_value = details.get("score") if isinstance(score_value, list) and len(score_value) > 0: score = score_value[0] else: score = score_value # Round score to 2 decimal places for readability if score is not None: score = round(float(score), 2) context_entry = { "Indicator": indicator, "Score": score, "Name": details.get("name"), "Country": summary.get("country") or details.get("country_name"), "ASN": summary.get("asn_name"), "ASNCode": summary.get("asn_code") or details.get("asn_code"), "CIDR": details.get("cidr"), "FirstSeen": details.get("first_seen_date"), "LastSeen": details.get("last_seen_date"), "SignalStrength": details.get("ioc_signal_strength") or raw_response.get("ioc_signal_strength"), "Confidence": details.get("cross_source_confidence") or raw_response.get("cross_source_confidence"), "IsWhitelisted": details.get("is_whitelisted", False), # Activity labels "Activity": { "Last1Day": activity_labels.get("last_1_day"), "Last7Days": activity_labels.get("last_7_days"), "Last30Days": activity_labels.get("last_30_days"), "Last90Days": activity_labels.get("last_90_days"), }, # Categorization flags "Categorization": { "CDN": categorization.get("cdn", False), "Cloud": categorization.get("cloud", False), "Cryptocurrency": categorization.get("cryptocurrency", False), "Honeypot": categorization.get("honeypot", False), "Hosting": categorization.get("hosting", False), "Malware": categorization.get("malware", False), "Proxy": categorization.get("proxy", False), "Scanner": categorization.get("scanner", False), "ThreatActor": categorization.get("threat_actor", False), "Tor": categorization.get("tor", False), "VPN": categorization.get("vpn", False), }, # Classifications "Classifications": { "Campaign": classifications.get("campaign"), "Country": classifications.get("country"), "Industries": classifications.get("industries", []), "Malwares": classifications.get("malwares", []), "Region": classifications.get("region"), "TargetCountries": classifications.get("target_country_list", []), "ThreatActors": classifications.get("threat_actors", []), }, # Premium Feeds "PremiumFeeds": [ { "Name": feed.get("name"), "Category": feed.get("category"), "Description": feed.get("description"), } for feed in premium_feeds ], # Relations (limited to 10) "Relations": [ { "Name": rel.get("name"), "Type": rel.get("relation_type"), "Source": rel.get("relation_source"), "FirstSeen": rel.get("first_seen_date"), } for rel in relations[:10] ], # History (limited to last 10 events) "History": [], } # Process history indicator_history = history.get("indicator_history", []) # Ensure indicator_history is a list before slicing if isinstance(indicator_history, list): for event in indicator_history[:10]: # Limit to 10 most recent events if isinstance(event, dict): # Ensure event is a dict context_entry["History"].append( { "Event": event.get("event"), "FeedSource": event.get("feed_source"), "Date": event.get("insert_date"), } ) # AI Insight (only if present in response) ai_insight = raw_response.get("socradar_copilot:ioc_agent") if ai_insight: context_entry["AIInsight"] = ai_insight return context_entry def detect_indicator_type(indicator: str) -> str: """Detect indicator type""" indicator = indicator.strip() if indicator.startswith(("http://", "https://")): return "url" if Validator.validate_ipv4(indicator) or Validator.validate_ipv6(indicator): return "ip" if Validator.validate_hash(indicator): return "file" if Validator.validate_domain(indicator): return "domain" raise ValueError(f"Unable to determine indicator type for: {indicator}") """ COMMAND FUNCTIONS """ def test_module(client: Client) -> str: """Tests API connectivity and authentication""" try: demisto.debug("Starting test_module...") response = client.check_auth() demisto.debug(f"Test response received: {response}") if response: demisto.debug("Test successful") return "ok" else: demisto.error("Test failed: No response") raise DemistoException("API test failed: No response from API") except DemistoException: raise except Exception as e: demisto.error(f"Test module exception: {str(e)}") error_details = f"Connection failed: {str(e)}\n\n" error_details += "Please check:\n" error_details += "1. API Key is correct\n" error_details += "2. Network connectivity to platform.socradar.com\n" error_details += "3. Firewall allows HTTPS outbound connections" raise DemistoException(error_details) def ip_command(client: Client, args: dict[str, Any], reliability: str = None) -> list[CommandResults]: """Returns SOCRadar IoC enrichment for IP addresses""" ips = args.get("ip", "") ip_list: list = argToList(ips) command_results_list: list[CommandResults] = [] for ip in ip_list: try: Validator.raise_if_ip_not_valid(ip) raw_response = client.get_indicator_enrichment(ip) if raw_response: details = raw_response.get("details", {}) score = details.get("score", 0) dbot_score_value = calculate_dbot_score(score) title = f"SOCRadar IoC Enrichment - Analysis for IP: {ip}" context_entry = build_entry_context(raw_response, ip) human_readable = tableToMarkdown(title, context_entry) dbot_score = Common.DBotScore( indicator=ip, indicator_type=DBotScoreType.IP, integration_name=INTEGRATION_NAME, score=dbot_score_value, reliability=reliability, ) ip_object = Common.IP(ip=ip, dbot_score=dbot_score) command_results_list.append( CommandResults( outputs_prefix="SOCRadarIoCEnrichment.IP", outputs_key_field="Indicator", readable_output=human_readable, raw_response=raw_response, outputs=context_entry, indicator=ip_object, ) ) else: message = f"No enrichment data found for IP: {ip}" command_results_list.append(CommandResults(readable_output=message)) except ValueError as e: command_results_list.append(CommandResults(readable_output=str(e))) except Exception as e: command_results_list.append(CommandResults(readable_output=f"Error processing IP {ip}: {str(e)}")) return command_results_list def domain_command(client: Client, args: dict[str, Any], reliability: str = None) -> list[CommandResults]: """Returns SOCRadar IoC enrichment for domains""" domains = args.get("domain", "") domain_list: list = argToList(domains) command_results_list: list[CommandResults] = [] for domain in domain_list: try: Validator.raise_if_domain_not_valid(domain) raw_response = client.get_indicator_enrichment(domain) if raw_response: details = raw_response.get("details", {}) score = details.get("score", 0) dbot_score_value = calculate_dbot_score(score) title = f"SOCRadar IoC Enrichment - Analysis for Domain: {domain}" context_entry = build_entry_context(raw_response, domain) human_readable = tableToMarkdown(title, context_entry) dbot_score = Common.DBotScore( indicator=domain, indicator_type=DBotScoreType.DOMAIN, integration_name=INTEGRATION_NAME, score=dbot_score_value, reliability=reliability, ) domain_object = Common.Domain(domain=domain, dbot_score=dbot_score) command_results_list.append( CommandResults( outputs_prefix="SOCRadarIoCEnrichment.Domain", outputs_key_field="Indicator", readable_output=human_readable, raw_response=raw_response, outputs=context_entry, indicator=domain_object, ) ) else: message = f"No enrichment data found for domain: {domain}" command_results_list.append(CommandResults(readable_output=message)) except ValueError as e: command_results_list.append(CommandResults(readable_output=str(e))) except Exception as e: command_results_list.append(CommandResults(readable_output=f"Error processing domain {domain}: {str(e)}")) return command_results_list def url_command(client: Client, args: dict[str, Any], reliability: str = None) -> list[CommandResults]: """Returns SOCRadar IoC enrichment for URLs""" urls = args.get("url", "") url_list: list = argToList(urls) command_results_list: list[CommandResults] = [] for url in url_list: try: Validator.raise_if_url_not_valid(url) raw_response = client.get_indicator_enrichment(url) if raw_response: details = raw_response.get("details", {}) score = details.get("score", 0) dbot_score_value = calculate_dbot_score(score) title = f"SOCRadar IoC Enrichment - Analysis for URL: {url}" context_entry = build_entry_context(raw_response, url) human_readable = tableToMarkdown(title, context_entry) dbot_score = Common.DBotScore( indicator=url, indicator_type=DBotScoreType.URL, integration_name=INTEGRATION_NAME, score=dbot_score_value, reliability=reliability, ) url_object = Common.URL(url=url, dbot_score=dbot_score) command_results_list.append( CommandResults( outputs_prefix="SOCRadarIoCEnrichment.URL", outputs_key_field="Indicator", readable_output=human_readable, raw_response=raw_response, outputs=context_entry, indicator=url_object, ) ) else: message = f"No enrichment data found for URL: {url}" command_results_list.append(CommandResults(readable_output=message)) except ValueError as e: command_results_list.append(CommandResults(readable_output=str(e))) except Exception as e: command_results_list.append(CommandResults(readable_output=f"Error processing URL {url}: {str(e)}")) return command_results_list def file_command(client: Client, args: dict[str, Any], reliability: str = None) -> list[CommandResults]: """Returns SOCRadar IoC enrichment for file hashes""" file_hashes = args.get("file", "") file_hash_list: list = argToList(file_hashes) command_results_list: list[CommandResults] = [] for hash_value in file_hash_list: try: Validator.raise_if_hash_not_valid(hash_value) hash_type = get_hash_type(hash_value) raw_response = client.get_indicator_enrichment(hash_value) if raw_response: details = raw_response.get("details", {}) score = details.get("score", 0) dbot_score_value = calculate_dbot_score(score) title = f"SOCRadar IoC Enrichment - Analysis for Hash: {hash_value}" context_entry = build_entry_context(raw_response, hash_value) human_readable = tableToMarkdown(title, context_entry) dbot_score = Common.DBotScore( indicator=hash_value, indicator_type=DBotScoreType.FILE, integration_name=INTEGRATION_NAME, score=dbot_score_value, reliability=reliability, ) file_object = Common.File(dbot_score=dbot_score) if hash_type == "sha256": file_object.sha256 = hash_value elif hash_type == "sha1": file_object.sha1 = hash_value elif hash_type == "md5": file_object.md5 = hash_value command_results_list.append( CommandResults( outputs_prefix="SOCRadarIoCEnrichment.File", outputs_key_field="Indicator", readable_output=human_readable, raw_response=raw_response, outputs=context_entry, indicator=file_object, ) ) else: message = f"No enrichment data found for hash: {hash_value}" command_results_list.append(CommandResults(readable_output=message)) except ValueError as e: command_results_list.append(CommandResults(readable_output=str(e))) except Exception as e: command_results_list.append(CommandResults(readable_output=f"Error processing hash {hash_value}: {str(e)}")) return command_results_list def socradar_ioc_enrichment_command(client: Client, args: dict[str, Any], reliability: str = None) -> list[CommandResults]: """Generic enrichment command for any indicator type with auto-detection""" indicator = args.get("indicator", "").strip() if not indicator: return [CommandResults(readable_output="Indicator parameter is required.")] command_results_list: list[CommandResults] = [] try: # Detect indicator type indicator_type = detect_indicator_type(indicator) # Get enrichment data raw_response = client.get_indicator_enrichment(indicator) if raw_response: details = raw_response.get("details", {}) # Extract score score_value = details.get("score") if isinstance(score_value, list) and len(score_value) > 0: score = score_value[0] else: score = score_value or 0 dbot_score_value = calculate_dbot_score(score) # Initialize common_object common_object: Common.IP | Common.Domain | Common.URL | Common.File | None = None # Determine DBot type based on detected type if indicator_type == "ip": dbot_type = DBotScoreType.IP output_prefix = "SOCRadarIoCEnrichment.IP" common_object = Common.IP( ip=indicator, dbot_score=Common.DBotScore( indicator=indicator, indicator_type=dbot_type, integration_name=INTEGRATION_NAME, score=dbot_score_value, reliability=reliability, ), ) elif indicator_type == "domain": dbot_type = DBotScoreType.DOMAIN output_prefix = "SOCRadarIoCEnrichment.Domain" common_object = Common.Domain( domain=indicator, dbot_score=Common.DBotScore( indicator=indicator, indicator_type=dbot_type, integration_name=INTEGRATION_NAME, score=dbot_score_value, reliability=reliability, ), ) elif indicator_type == "url": dbot_type = DBotScoreType.URL output_prefix = "SOCRadarIoCEnrichment.URL" common_object = Common.URL( url=indicator, dbot_score=Common.DBotScore( indicator=indicator, indicator_type=dbot_type, integration_name=INTEGRATION_NAME, score=dbot_score_value, reliability=reliability, ), ) else: # file/hash dbot_type = DBotScoreType.FILE output_prefix = "SOCRadarIoCEnrichment.File" hash_type = get_hash_type(indicator) dbot_score = Common.DBotScore( indicator=indicator, indicator_type=dbot_type, integration_name=INTEGRATION_NAME, score=dbot_score_value, reliability=reliability, ) common_object = Common.File(dbot_score=dbot_score) if hash_type == "sha256": common_object.sha256 = indicator elif hash_type == "sha1": common_object.sha1 = indicator elif hash_type == "md5": common_object.md5 = indicator title = f"SOCRadar IoC Enrichment - {indicator_type.upper()}: {indicator}" context_entry = build_entry_context(raw_response, indicator) human_readable = tableToMarkdown(title, context_entry) command_results_list.append( CommandResults( outputs_prefix=output_prefix, outputs_key_field="Indicator", readable_output=human_readable, raw_response=raw_response, outputs=context_entry, indicator=common_object, ) ) else: message = f"No enrichment data found for indicator: {indicator}" command_results_list.append(CommandResults(readable_output=message)) except ValueError as e: command_results_list.append(CommandResults(readable_output=f"Error: {str(e)}")) except Exception as e: command_results_list.append(CommandResults(readable_output=f"Error processing indicator {indicator}: {str(e)}")) return command_results_list """ MAIN FUNCTION """ def main() -> None: """main function, parses params and runs command functions""" params = demisto.params() api_key = params.get("apikey", {}).get("password") base_url = SOCRADAR_API_ENDPOINT verify_certificate = not params.get("insecure", False) proxy = params.get("proxy", False) reliability = params.get("integrationReliability") include_ai_insights = params.get("include_ai_insights", False) demisto.debug(f"Command being called is {demisto.command()}") try: client = Client( base_url=base_url, api_key=api_key, verify=verify_certificate, proxy=proxy, include_ai_insights=include_ai_insights, ) command = demisto.command() if command == "test-module": demisto.debug("Executing test-module command") result = test_module(client) demisto.debug(f"Test module result: {result}") return_results(result) elif command == "ip": demisto.debug("Executing ip command") return_results(ip_command(client, demisto.args(), reliability)) elif command == "domain": demisto.debug("Executing domain command") return_results(domain_command(client, demisto.args(), reliability)) elif command == "url": demisto.debug("Executing url command") return_results(url_command(client, demisto.args(), reliability)) elif command == "file": demisto.debug("Executing file command") return_results(file_command(client, demisto.args(), reliability)) elif command == "socradar-ioc-enrichment": demisto.debug("Executing socradar-ioc-enrichment command") return_results(socradar_ioc_enrichment_command(client, demisto.args(), reliability)) else: demisto.debug(f"Unknown command: {command}") return_error(f"Command {command} is not supported") except Exception as e: demisto.error(traceback.format_exc()) return_error(f"Failed to execute {demisto.command()} command.\nError:\n{str(e)}") """ ENTRY POINT """ if __name__ in ("__main__", "__builtin__", "builtins"): main()