DHS Feed v2
The Cybersecurity and Infrastructure Security Agency’s (CISA’s) free Automated Indicator Sharing (AIS) capability enables the exchange of cyber threat indicators, at machine speed, to the Federal Government community.
Data Enrichment & Threat Intelligence · DHS Feed · Feed
Details
| ID | DHS Feed v2 |
|---|---|
| Provider | DHS |
| Category | Data Enrichment & Threat Intelligence |
| From Version | 6.5.0 |
| Docker Image | demisto/taxii2:1.0.0.9117276 |
| Supported Modules | Agentix XSIAM |
README
The Cybersecurity and Infrastructure Security Agency’s (CISA’s) free Automated Indicator Sharing (AIS) capability enables the exchange of cyber threat indicators, at machine speed, to the Federal Government community.
Use this version if your certificate supports TAXII 2 protocol.
Some changes have been made that might affect your existing content.
If you are upgrading from a previous version of this integration, see Breaking Changes.
Configure DHS Feed v2 in Cortex
| Parameter | Description | Required |
|---|---|---|
| Fetch indicators | False | |
| Discovery Service URL (e.g., https://ais2.cisa.dhs.gov/taxii2/) | True | |
| Key File as Text | For more information, visit https://us-cert.cisa.gov/ais. | True |
| Certificate File as Text | For more information, visit https://us-cert.cisa.gov/ais. | True |
| Default API Root to use | The default API root to use (e.g., default, public). If left empty, the server default API root will be used. When the server has no default root, the first available API root will be used instead. The user must be authorized to reach the selected API root. | False |
| Collection Name To Fetch Indicators From | Indicators will be fetched from this collection. Run the “dhs-get-collections” command to get a valid value. If left empty, the instance will try to fetch from all the collections in the given discovery service. | 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 |
| Traffic Light Protocol Color | The Traffic Light Protocol (TLP) designation to apply to indicators fetched from the feed. | False |
| Feed Fetch Interval | False | |
| First Fetch Time | The time interval for the first fetch (retroactive) in the following format: <number> <time unit> of type minute/hour/day. For example, 1 minute, 12 hour. Limited to 48 hours. | False |
| STIX Objects To Fetch | The objects to fetch, most likely indicators. Might slow down fetch time. | False |
| Trust any certificate (not secure) | False | |
| Use system proxy settings | 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 |
| Max Indicators Per Fetch | The maximum number of indicators that can be fetched per fetch. If this field is left empty, there will be no limit on the number of indicators fetched. | False |
| Max STIX Objects Per Poll | Set the number of STIX objects that will be requested with each TAXII poll (http request). A single fetch is made of several TAXII polls. Changing this setting can help speed up fetches, or fix issues on slower networks. Please note server restrictions may apply, overriding and limiting the requested limit. | False |
| Complex Observation Mode | Choose how to handle complex observations. Two or more Observation Expressions MAY be combined using a complex observation operator such as “AND”, “OR”. For example, `[ IP = ‘b’ ] AND [ URL = ‘d’ ]` | False |
| Tags | Supports CSV values. | 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.
dhs-get-indicators
Allows you to test your feed and to make sure you can fetch indicators successfully.
Due to API limitations, running this command may take longer than the default 5 minutes.
To overcome this issue increase the execution-timeout from 300 seconds to a higher value, the recommended value is 1800 seconds.
Base Command
dhs-get-indicators
Input
| Argument Name | Description | Required |
|---|---|---|
| raw | Will return only the rawJSON of the indicator object. Possible values are: true, false. Default is false. | Optional |
| limit | Maximum number of indicators to return. Default is 10. | Optional |
| added_after | Fetch only indicators that were added to the server after the given time. Provide a <number> and <time unit> of type minute/hour/day. For example, 1 minute, 12 hour, 24 days. Limited to 48 hours. Default is 24 hours. | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| DHS.Indicators.value | String | Indicator value. |
| DHS.Indicators.type | String | Indicator type. |
| DHS.Indicators.rawJSON | String | Indicator rawJSON. |
Command Example
!dhs-get-indicators limit=3 execution-timeout=1800
Context Example
{
"DHS.Indicators": [
{
"fields": {
"tags": [
"cisa-proprietary-false"
]
},
"rawJSON": {
"created": "2021-08-09T00:42:54.000Z",
"created_by_ref": "identity--e8",
"id": "indicator--e0",
"indicator_types": [
"anomalous-activity",
"attribution"
],
"labels": [
"cisa-proprietary-false"
],
"modified": "2021-09-26T04:16:13.000Z",
"name": "sometimes",
"object_marking_refs": [
"marking-definition--633",
"marking-definition--f51"
],
"pattern": "[domain-name:value = 'coronashop.jp']",
"pattern_type": "stix",
"pattern_version": "2.1",
"spec_version": "2.1",
"type": "Domain",
"valid_from": "2021-09-26T00:09:38Z",
"value": "coronashop.jp"
},
"type": "Domain",
"value": "coronashop.jp"
},
{
"fields": {
"description": "A totally famous IP Address",
"tags": [
"elevated"
]
},
"rawJSON": {
"created": "2022-03-01T14:17:59.000Z",
"created_by_ref": "identity--a9",
"description": "A totally famous IP Address",
"id": "indicator--2f5",
"labels": [
"elevated"
],
"modified": "2022-03-01T14:17:59.000Z",
"object_marking_refs": [
"marking-definition--633"
],
"pattern": "[ipv4-addr:value = '1.1.1.1']",
"pattern_type": "stix",
"spec_version": "2.1",
"type": "IP",
"valid_from": "2022-03-01T14:17:59.000000Z",
"value": "1.1.1.1"
},
"type": "IP",
"value": "1.1.1.1"
},
{
"fields": {
"tags": [
"elevated"
]
},
"rawJSON": {
"created": "2022-02-28T13:18:49.000Z",
"created_by_ref": "identity--8c4",
"id": "indicator--9a6",
"indicator_types": [
"file-hash-watchlist"
],
"labels": [
"elevated"
],
"modified": "2022-02-28T13:18:49.000Z",
"object_marking_refs": [
"marking-definition--633"
],
"pattern": "[file:hashes.MD5 = 'e6ecb146f469d243945ad8a5451ba1129c5b190f7d50c64580dbad4b8246f88e']",
"pattern_type": "stix",
"spec_version": "2.1",
"type": "File",
"valid_from": "2022-02-28T13:18:49.000000Z",
"value": "e6ecb146f469d243945ad8a5451ba1129c5b190f7d50c64580dbad4b8246f88e"
},
"type": "File",
"value": "e6ecb146f469d243945ad8a5451ba1129c5b190f7d50c64580dbad4b8246f88e"
}
]
}
Human Readable Output
Found 3 results added after 2022-12-07T10:29:13.079493Z UTC:
DHS Indicators
value type coronashop.jp Domain 1.1.1.1 IP e6ecb146f469d243945ad8a5451ba1129c5b190f7d50c64580dbad4b8246f88e File
dhs-get-collections
Gets the list of collections from the discovery service.
Base Command
dhs-get-collections
Input
There are no input arguments for this command.
Context Output
| Path | Type | Description |
|---|---|---|
| DHS.Collections.ID | String | Collection ID. |
| DHS.Collections.Name | String | Collection name. |
Command Example
#### Context Example
```json
{
"DHS.Collections": [
{
"ID": "3",
"Name": "Public Collection"
}
]
}
Human Readable Output
DHS Server Collections
Name ID Public Collection 3
Breaking Changes
The following are the breaking changes from the previous version of this integration.
Arguments
The following argument was removed in this version
In the dhs-get-indicators command, tlp_colorwas removed.
The behavior of the following arguments was changed
In the dhs-get-indicators command, the default value of the limit argument was changed to ‘10’.
Outputs
The following outputs were removed in this version
In the dhs-get-indicators command:
- DHS.type - this output was replaced by DHS.Indicators.type.
- DHS.value - this output was replaced by DHS.Indicators.value.
- DHS.tlp - this output was removed.
Additional Considerations for this version
Use this version if your certificate supports TAXII 2 protocol.
Known Limitations
“First Fetch Time” parameter can be configured for a maximum of 48 hours, due to limitations in DHS TAXII2 API.
Therefore, it is not possible to fetch indicators that last appeared in the feed more than 48 hours ago.
Configuration parameters
feed— Fetch indicatorsurl— Discovery Service URL (e.g., https://ais2.cisa.dhs.gov/taxii2/) (required)key— (required)certificate— Certificate File as Text (required)default_api_root— Default API Root to usecollection_to_fetch— Collection Name To Fetch Indicators FromfeedReputation— Indicator ReputationfeedReliability— Source Reliability (required)tlp_color— Traffic Light Protocol ColorfeedExpirationPolicy—feedExpirationInterval—feedFetchInterval— Feed Fetch Intervalinitial_interval— First Fetch Timeobjects_to_fetch— STIX Objects To Fetchinsecure— Trust any certificate (not secure)proxy— Use system proxy settingsfeedBypassExclusionList— Bypass exclusion listlimit— Max Indicators Per Fetchlimit_per_request— Max STIX Objects Per Pollobservation_operator_mode— Complex Observation ModefeedTags— TagsfeedIncremental— Incremental Feed
Commands (2)
-
dhs-get-collectionsGets the list of collections from the discovery service.
-
dhs-get-indicatorsAllows you to test your feed and to make sure you can fetch indicators successfully. Due to API limitations, this command may take a long time to run. Make sure the 'execution-timeout' argument is increased. See the integration readme for further information.
import demistomock as demisto # noqa: F401 from CommonServerPython import * # noqa: F401 from pytz import utc from TAXII2ApiModule import * # noqa: E402 from taxii2client.common import _ensure_datetime_to_string """ CONSTANTS """ COMPLEX_OBSERVATION_MODE_SKIP = "Skip indicators with more than a single observation" MAX_FETCH_INTERVAL = "48 hours" DEFAULT_FETCH_INTERVAL = "24 hours" DEFAULT_LIMIT_PER_REQUEST = 1000 # DHS default limit """ HELPER FUNCTIONS """ def get_datetime(given_interval: Union[str, datetime]) -> datetime: """ Receives an interval and returns the corresponding datetime. """ if isinstance(given_interval, datetime): return given_interval date = dateparser.parse(given_interval, date_formats=[TAXII_TIME_FORMAT]) if not date: raise DemistoException("Given time interval is not in a valid format.") return date.replace(tzinfo=utc) # type: ignore[union-attr] def get_limited_interval( given_interval: Union[str, datetime], fetch_interval: Optional[Union[str, datetime]] = MAX_FETCH_INTERVAL ) -> datetime: """ Returns the closer time between the two time intervals given. """ given_interval: datetime = get_datetime(given_interval) fetch_interval: datetime = get_datetime(fetch_interval or MAX_FETCH_INTERVAL) return max(given_interval, fetch_interval) # later time is bigger def fetch_one_collection(client: Taxii2FeedClient, limit: int, initial_interval: datetime, last_run_ctx: Optional[dict] = None): demisto.debug(f"Fetching collection {client.collection_to_fetch.id=}") last_fetch_time = last_run_ctx.get(client.collection_to_fetch.id) if last_run_ctx else None # initial_interval gets here limited so no need to check limitation with default value added_after: datetime = get_limited_interval(initial_interval, last_fetch_time) indicators = client.build_iterator(limit, added_after=added_after) if last_run_ctx is not None: # in case we got {}, we want to set it because we are in fetch incident run last_run_ctx[client.collection_to_fetch.id] = _ensure_datetime_to_string( client.last_fetched_indicator__modified if client.last_fetched_indicator__modified else added_after ) return indicators, last_run_ctx def fetch_all_collections(client: Taxii2FeedClient, limit: int, initial_interval: datetime, last_run_ctx: Optional[dict] = None): indicators: list = [] for collection in client.collections: # type: ignore[attr-defined] client.collection_to_fetch = collection fetched_iocs, last_run_ctx = fetch_one_collection(client, limit, initial_interval, last_run_ctx) indicators.extend(fetched_iocs) if limit >= 0: limit -= len(fetched_iocs) if limit <= 0: break return indicators, last_run_ctx """ COMMAND FUNCTIONS """ def command_test_module(client: Taxii2FeedClient, initial_interval: str): if get_datetime(MAX_FETCH_INTERVAL) > get_datetime(initial_interval): return 'Due to DHS API limitations, "First Fetch Time" is limited to 48 hours.' try: client.initialise() if client.collections: get_indicators_command(client, {"limit": "1", "added_after": get_limited_interval("6 hours", initial_interval)}) else: return "Could not connect to server" except requests.exceptions.ConnectTimeout: return ( "Connection Timeout Error - potential reasons might be that the 'Discovery Service URL' parameter" " is incorrect or that the server is not accessible from your host." ) except requests.exceptions.SSLError: return ( "SSL Certificate Verification Failed - try selecting 'Trust any certificate' checkbox in" " the instance configuration. If this doesn't work, verify that your certificate and key are valid and matching." ) except requests.exceptions.ProxyError: return ( "Proxy Error - if the 'Use system proxy' checkbox in the integration configuration is" " selected, try clearing the checkbox." ) except requests.exceptions.ConnectionError: return ( "Verify that the server URL parameter is correct and that you have access to the server from your host." " Run the test again." ) except requests.HTTPError: return ( "HTTP error - check your certificate and key, and that you are trying to reach a valid URL and API root." " Wait and run the test again." ) return "ok" def fetch_indicators_command( client: Taxii2FeedClient, limit: int, last_run_ctx: dict, initial_interval: str = DEFAULT_FETCH_INTERVAL ) -> tuple[list, dict]: """ Fetch indicators from TAXII 2 server :param client: Taxii2FeedClient :param limit: upper limit of indicators to fetch :param last_run_ctx: last run dict with {collection_id: last_run_time string} :param initial_interval: initial interval in human readable format :return: indicators in cortex TIM format, updated last_run_ctx """ initial_interval: datetime = get_limited_interval(get_datetime(initial_interval or DEFAULT_FETCH_INTERVAL)) if client.collection_to_fetch: indicators, last_run_ctx = fetch_one_collection(client, limit, initial_interval, last_run_ctx) # type: ignore[arg-type] else: indicators, last_run_ctx = fetch_all_collections(client, limit, initial_interval, last_run_ctx) # type: ignore[arg-type] return indicators, last_run_ctx def get_indicators_command( client: Taxii2FeedClient, args: Dict[str, Any] ) -> Union[CommandResults, Dict[str, List[Optional[str]]]]: """ Fetch indicators from TAXII 2 server :param client: Taxii2FeedClient :param args: Dict that holds raw: When set to 'true' will return only rawJSON limit: upper limit of indicators to fetch added_after: added after time string in parse_date_range format :return: indicators in cortex TIM format """ limit = arg_to_number(args.get("limit")) or 10 raw = argToBoolean(args.get("raw", "false")) max_fetch_datetime = get_datetime(MAX_FETCH_INTERVAL) added_after: datetime = get_datetime(args.get("added_after", DEFAULT_FETCH_INTERVAL)) if max_fetch_datetime > added_after: raise DemistoException('Due to DHS API limitations, "added_after" is limited to 48 hours.') if client.collection_to_fetch: indicators = client.build_iterator(limit, added_after=added_after) else: indicators, _ = fetch_all_collections(client, limit, added_after) # type: ignore[arg-type] if raw: return {"indicators": [x.get("rawJSON") for x in indicators]} return CommandResults( readable_output=f"Found {len(indicators)} results added after {_ensure_datetime_to_string(added_after)} UTC:\n" + tableToMarkdown(name="DHS Indicators", t=indicators, headers=["value", "type"], removeNull=True), outputs_prefix="DHS.Indicators", outputs_key_field="value", outputs=indicators, raw_response=indicators, ) def get_collections_command(client: Taxii2FeedClient) -> CommandResults: """ Get the available collections in the DHS server """ collections = [] for collection in client.collections: # type: ignore[attr-defined] collections.append({"Name": collection.title, "ID": collection.id}) return CommandResults( readable_output=tableToMarkdown("DHS Server Collections", t=collections, headers=["Name", "ID"]), outputs_prefix="DHS.Collections", outputs_key_field="ID", outputs=collections, ) """ MAIN FUNCTION """ def main(): # pragma: no cover params = demisto.params() url = params.get("url", "https://ais2.cisa.dhs.gov/taxii2/") key = params.get("key", {}).get("password") certificate = params.get("certificate") verify_certificate = not params.get("insecure", False) proxies = handle_proxy() collection_to_fetch = params.get("collection_to_fetch") skip_complex_mode = params.get("observation_operator_mode") == COMPLEX_OBSERVATION_MODE_SKIP feed_tags = argToList(params.get("feedTags")) tlp_color = params.get("tlp_color", "") objects_to_fetch = params.get("objects_to_fetch", []) initial_interval = params.get("initial_interval", DEFAULT_FETCH_INTERVAL) limit = arg_to_number(params.get("limit", -1)) or -1 limit_per_request = arg_to_number(params.get("limit_per_request", DEFAULT_LIMIT_PER_REQUEST)) or DEFAULT_LIMIT_PER_REQUEST default_api_root = params.get("default_api_root", "public") command = demisto.command() demisto.info(f"Command being called is {command}") try: client = Taxii2FeedClient( url=url, collection_to_fetch=collection_to_fetch, proxies=proxies, verify=verify_certificate, objects_to_fetch=objects_to_fetch, skip_complex_mode=skip_complex_mode, tags=feed_tags, limit_per_request=limit_per_request, tlp_color=tlp_color, certificate=certificate, key=key, default_api_root=default_api_root, ) start_time = time.time() if command == "test-module": return_results(command_test_module(client, initial_interval)) elif command == "fetch-indicators": client.initialise() last_run_indicators = demisto.getLastRun() indicators, last_run_indicators = fetch_indicators_command(client, limit, last_run_indicators, initial_interval) for iter_ in batch(indicators, batch_size=2000): demisto.createIndicators(iter_) demisto.setLastRun(last_run_indicators) elif command == "dhs-get-indicators": client.initialise() return_results(get_indicators_command(client, demisto.args())) elif command == "dhs-get-collections": client.initialise() return_results(get_collections_command(client)) else: raise NotImplementedError(f"{command} command is not implemented.") demisto.debug(f"Running {command} took {round(time.time() - start_time)}sec") except Exception as error: error_msg = str(error) if isinstance(error, requests.exceptions.SSLError): error_msg = ( "Encountered an HTTPS certificate error. This error can be ignored by enabling " '"Trust any certificate (not secure)" in the instance configuration.' ) elif isinstance(error, requests.HTTPError): error_msg = ( "Encountered an HTTP error. Please check your certificate and key, and that you are trying to reach a " 'valid URL and API root. If this occurs when the test works, increase the "Max STIX Objects Per Poll" ' 'in the instance configuration, reduce the "Max Indicators Per Fetch" in the instance configuration or ' 'reduce the "limit" in the command argument.' ) return_error(error_msg, error) """ ENTRY POINT """ if __name__ in ("__main__", "builtins"): main()