Proofpoint Threat Response
Use the Proofpoint Threat Response integration to orchestrate and automate incident response.
Network Security · Proofpoint Threat Response
Details
| ID | Proofpoint Threat Response |
|---|---|
| Provider | Thoma Bravo |
| Category | Network Security |
| From Version | 5.0.0 |
| Docker Image | demisto/python3:3.12.13.10116658 |
| Supported Modules | Agentix XSIAM EDR Cortex Cloud Cloud Runtime Security |
README
Use the Proofpoint Threat Response integration to orchestrate and automate incident response.
Configure Proofpoint Threat Response in Cortex
| Parameter | Description | Required |
|---|---|---|
| Server URL (e.g. https://192.168.0.1) | True | |
| API Key | True | |
| Trust any certificate (not secure) | False | |
| Use system proxy settings | False | |
| Fetch incidents | False | |
| Incident type | False | |
| First fetch timestamp (“number” “time unit”, e.g., 12 hours, 7 days) | The time range for the initial data fetch. If timeout errors occur, consider changing this value. | False |
| Fetch limit - maximum number of incidents per fetch | False | |
| Fetch delta - The delta time in each batch. e.g. 1 hour, 3 minutes. | The time range between create_after and created_before that is sent to the API when fetching older incidents. If timeout errors occur, consider changing this value. | False |
| Fetch incidents with specific event sources. Can be a list of comma separated values. | False | |
| Fetch incidents with specific ‘Abuse Disposition’ values. Can be a list of comma separated values. | False | |
| Fetch incident with specific states. | False | |
| POST URL of the JSON alert source. | You can find this value by navigating to Sources -> JSON event source -> POST URL. | 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.
proofpoint-tr-get-list
Gets items for the specified list.
Base Command
proofpoint-tr-get-list
Input
| Argument Name | Description | Required |
|---|---|---|
| list-id | The ID of the list. | Required |
Context Output
There is no context output for this command.
proofpoint-tr-add-to-list
Adds a member to the specified list.
Base Command
proofpoint-tr-add-to-list
Input
| Argument Name | Description | Required |
|---|---|---|
| list-id | The list to add a member to. | Required |
| indicator | A comma-separated list of indicator values. Can be IP addresses, URLs, domains, or file hashes. For example: “192.168.1.1,192.168.1.2”. |
Required |
| comment | A comment about the member. | Optional |
| expiration | The expiration of the member. | Optional |
Context Output
There is no context output for this command.
proofpoint-tr-block-ip
Adds the supplied IP addresses to the specified IP block list.
Base Command
proofpoint-tr-block-ip
Input
| Argument Name | Description | Required |
|---|---|---|
| ip | A comma-separated list of IP addresses to block list. | Required |
| expiration | The date and time the supplied IP addresses should be removed from the block list, in the format YYYY-MM-DDTHH:MM:SSZ. For example: 2020-02-02T19:00:00Z. |
Optional |
| blacklist_ip | The ID of the IP block list. | Required |
Context Output
There is no context output for this command.
proofpoint-tr-block-domain
Adds the supplied domains to the specified block list.
Base Command
proofpoint-tr-block-domain
Input
| Argument Name | Description | Required |
|---|---|---|
| domain | A comma-separated list of domains to add to the block list. | Required |
| expiration | The date and time the supplied IP addresses should be removed from the block list, in the format YYYY-MM-DDTHH:MM:SSZ. For example: 2020-02-02T19:00:00Z. |
Optional |
| blacklist_domain | The ID of the domain block list. | Required |
Context Output
There is no context output for this command.
proofpoint-tr-search-indicator
Returns indicators from the specified list, according to the defined filter.
Base Command
proofpoint-tr-search-indicator
Input
| Argument Name | Description | Required |
|---|---|---|
| list-id | The ID of the list in which to search. | Required |
| filter | The filter for the indicator search. For example, “1.1” will return [1.1.1.1, 22.22.1.1, 1.1.22.22]. |
Required |
Context Output
There is no context output for this command.
proofpoint-tr-delete-indicator
Deletes an indicator from the specified list.
Base Command
proofpoint-tr-delete-indicator
Input
| Argument Name | Description | Required |
|---|---|---|
| list-id | ID of the list from which to delete indicators. | Required |
| indicator | The indicator value to delete from the list. Can be an IP address, URL, domain, or file hash. For example: “demisto.com”. |
Required |
Context Output
There is no context output for this command.
proofpoint-tr-block-url
Adds the supplied URLs to the specified URL block list.
Base Command
proofpoint-tr-block-url
Input
| Argument Name | Description | Required |
|---|---|---|
| url | A comma-separated list of URLs to add to the URL block list. | Required |
| expiration | The date and time the supplied URLs should be removed from the block list, in the format YYYY-MM-DDTHH:MM:SSZ. For example: 2020-02-02T19:00:00Z. |
Optional |
| blacklist_url | The ID of the URL block list. | Required |
Context Output
There is no context output for this command.
proofpoint-tr-block-hash
Adds the supplied file hashes to the specified file hash block list.
Base Command
proofpoint-tr-block-hash
Input
| Argument Name | Description | Required |
|---|---|---|
| hash | A comma-separated list of file hashes to add to the file hash block list. | Required |
| expiration | The date and time the supplied file hashes should be removed from the block list, in the format YYYY-MM-DDTHH:MM:SSZ. For example: 2020-02-02T19:00:00Z. |
Optional |
| blacklist_hash | The ID of the hash block list. | Required |
Context Output
There is no context output for this command.
proofpoint-tr-list-incidents
Retrieves all incident metadata from Threat Response by specifying filter criteria such as the state of the incident or time of closure.
Base Command
proofpoint-tr-list-incidents
Input
| Argument Name | Description | Required |
|---|---|---|
| state | State of the incidents to retrieve. Possible values are: new, open, assigned, closed, ignored. | Optional |
| created_after | Retrieve incidents that were created after this date, in ISO 8601 format (UTC). Example: 2020-02-22 or 2020-02-22T00:00:00Z. Possible values are: . |
Optional |
| created_before | Retrieve incidents that were created before this date, in ISO 8601 format (UTC). Example: 2020-02-22 or 2020-02-22T00:00:00Z. |
Optional |
| closed_after | Retrieve incidents that were closed after this date, in ISO 8601 format (UTC). Example: 2020-02-22 or 2020-02-22T00:00:00Z. |
Optional |
| closed_before | Retrieve incidents that were closed before this date, in ISO 8601 format (UTC). Example: 2020-02-22 or 2020-02-22T00:00:00Z. |
Optional |
| expand_events | If false, will return an array of event IDs instead of full event objects. This will significantly speed up the response time of the API for incidents with large numbers of alerts. | Optional |
| limit | The maximum number of incidents to return. The default value is 50. | Required |
Context Output
| Path | Type | Description |
|---|---|---|
| ProofPointTRAP.Incident.id | Number | The incident ID. |
| ProofPointTRAP.Incident.summary | String | The summary of the incident. |
| ProofPointTRAP.Incident.score | Number | The score of the incident from Proofpoint. |
| ProofPointTRAP.Incident.state | String | The state of the incident. Can be - Open, Closed, New, Assigned, Ignored. |
| ProofPointTRAP.Incident.created_at | Date | The date the incident was created. |
| ProofPointTRAP.Incident.updated_at | Date | The date the incident was last updated. |
| ProofPointTRAP.Incident.event_count | Number | The number of events attached to the incident. |
| ProofPointTRAP.Incident.false_positive_count | Number | The number of false positive events in the incident. |
| ProofPointTRAP.Incident.event_sources | String | The sources of the events. |
| ProofPointTRAP.Incident.assignee | String | The user assigned to the incident. |
| ProofPointTRAP.Incident.team | String | The team assigned to the incident. |
| ProofPointTRAP.Incident.hosts.attacker | String | The host attacker. |
| ProofPointTRAP.Incident.hosts.forensics | String | The host forensics. |
| ProofPointTRAP.Incident.incident_field_values.Severity | String | The severity of the incident. |
| ProofPointTRAP.Incident.incident_field_values.Abuse_disposition | String | The abuse disposition of the incident. |
| ProofPointTRAP.Incident.incident_field_values.Attack_vector | String | The attack vector of the incident. |
| ProofPointTRAP.Incident.incident_field_values.Classification | String | The classification of the incident. |
| ProofPointTRAP.Incident.events.id | Number | The event ID. |
| ProofPointTRAP.Incident.events.category | String | The event category. |
| ProofPointTRAP.Incident.events.alertType | String | The alert type of the event. |
| ProofPointTRAP.Incident.events.severity | String | The severity of the event. |
| ProofPointTRAP.Incident.events.source | String | The source of the event. |
| ProofPointTRAP.Incident.events.state | String | The state of the event. |
| ProofPointTRAP.Incident.events.attackDirection | String | The attack direction of the event. |
| ProofPointTRAP.Incident.events.received | Date | The time the incident was received. |
| ProofPointTRAP.Incident.events.emails.sender | String | The sender of the email. |
| ProofPointTRAP.Incident.events.emails.recipient | String | The recipient of the email. |
| ProofPointTRAP.Incident.events.emails.message_Id | String | The message ID of the email. |
| ProofPointTRAP.Incident.events.emails.message_delivery_time | Number | The delivery time of the message. |
| ProofPointTRAP.Incident.events.attackers.location | String | The location of the attacker. |
| ProofPointTRAP.Incident.events.falsePositive | Boolean | Whether this incident is a false positive. |
| ProofPointTRAP.Incident.events.threatname | String | The threat name. |
| ProofPointTRAP.Incident.events.description | String | The description of the event. |
| ProofPointTRAP.Incident.events.malwareName | String | The malware name. |
| ProofPointTRAP.Incident.quarantine_results.alertSource | String | The alert source. |
| ProofPointTRAP.Incident.quarantine_results.startTime | Date | The start time of the result. |
| ProofPointTRAP.Incident.quarantine_results.endTime | Date | The end time of the result. |
| ProofPointTRAP.Incident.quarantine_results.status | String | The status of the result. |
| ProofPointTRAP.Incident.quarantine_results.recipientType | String | The recipient type. |
| ProofPointTRAP.Incident.quarantine_results.recipient | String | The recipient email address. |
| ProofPointTRAP.Incident.quarantine_results.messageId | String | The message ID. |
| ProofPointTRAP.Incident.quarantine_results.isRead | Boolean | Whether the message has been read. |
| ProofPointTRAP.Incident.quarantine_results.wasUndone | String | Whether the message was undone. |
| ProofPointTRAP.Incident.quarantine_results.details | String | The details about the result. |
| ProofPointTRAP.Incident.successful_quarantines | Number | The number of successful quarantines. |
| ProofPointTRAP.Incident.failed_quarantines | Number | The number of failed quarantines. |
| ProofPointTRAP.Incident.pending_quarantines | Number | The number of pending quarantines. |
| ProofPointTRAP.Incident.events.emails.body | String | The body of the email. |
| ProofPointTRAP.Incident.events.emails.body_type | String | The format of the body. |
| ProofPointTRAP.Incident.events.emails.headers | Unknown | The email headers. |
| ProofPointTRAP.Incident.events.emails.urls | Unknown | The list of URLs from the email. |
| ProofPoint.Incident.event_ids | Unknown | The list of IDs attached to the incident. |
proofpoint-tr-get-incident
Retrieves incident metadata from Threat Response.
Base Command
proofpoint-tr-get-incident
Input
| Argument Name | Description | Required |
|---|---|---|
| incident_id | The ID value of the incident to retrieve (e.g. for incident INC-4000, the input for this argument should be 4000). | Required |
| expand_events | If false, will return an array of event IDs instead of full event objects. This will significantly speed up the response time of the API for incidents with large numbers of alerts. | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| ProofPointTRAP.Incident.id | Number | The incident ID. |
| ProofPointTRAP.Incident.summary | String | The summary of the incident. |
| ProofPointTRAP.Incident.score | Number | The score of the incident from Proofpoint. |
| ProofPointTRAP.Incident.state | String | The state of the incident. Can be - Open, Closed, New, Assigned, Ignored. |
| ProofPointTRAP.Incident.created_at | Date | The date the incident was created. |
| ProofPointTRAP.Incident.updated_at | Date | The date the incident was last updated. |
| ProofPointTRAP.Incident.event_count | Number | The number of events attached to the incident. |
| ProofPointTRAP.Incident.false_positive_count | Number | The number of false positive events in the incident. |
| ProofPointTRAP.Incident.event_sources | String | The sources of the events. |
| ProofPointTRAP.Incident.assignee | String | The user assigned to the incident. |
| ProofPointTRAP.Incident.team | String | The team assigned to the incident. |
| ProofPointTRAP.Incident.hosts.attacker | String | The host attacker. |
| ProofPointTRAP.Incident.hosts.forensics | String | The host forensics. |
| ProofPointTRAP.Incident.incident_field_values.Severity | String | The severity of the incident. |
| ProofPointTRAP.Incident.incident_field_values.Abuse_disposition | String | The abuse disposition of the incident. |
| ProofPointTRAP.Incident.incident_field_values.Attack_vector | String | The attack vector of the incident. |
| ProofPointTRAP.Incident.incident_field_values.Classification | String | The classification of the incident. |
| ProofPointTRAP.Incident.events.id | Number | The event ID. |
| ProofPointTRAP.Incident.events.category | String | The event category. |
| ProofPointTRAP.Incident.events.alertType | String | The alert type of the event. |
| ProofPointTRAP.Incident.events.severity | String | The severity of the event. |
| ProofPointTRAP.Incident.events.source | String | The source of the event. |
| ProofPointTRAP.Incident.events.state | String | The state of the event. |
| ProofPointTRAP.Incident.events.attackDirection | String | The attack direction of the event |
| ProofPointTRAP.Incident.events.received | Date | The date the incident was received. |
| ProofPointTRAP.Incident.events.emails.sender | String | The sender of the email. |
| ProofPointTRAP.Incident.events.emails.recipient | String | The recipient of the email. |
| ProofPointTRAP.Incident.events.emails.message_Id | String | The message ID of the email. |
| ProofPointTRAP.Incident.events.emails.message_delivery_time | Number | The time the message was delivered. |
| ProofPointTRAP.Incident.events.attackers.location | String | The location of the attacker. |
| ProofPointTRAP.Incident.events.falsePositive | Boolean | Whether this incident is a false positive. |
| ProofPointTRAP.Incident.events.threatname | String | The threat name. |
| ProofPointTRAP.Incident.events.description | String | The description of the event. |
| ProofPointTRAP.Incident.events.malwareName | String | The malware name. |
| ProofPointTRAP.Incident.quarantine_results.alertSource | String | The alert source. |
| ProofPointTRAP.Incident.quarantine_results.startTime | Date | The start time of the result. |
| ProofPointTRAP.Incident.quarantine_results.endTime | Date | The end time of the result. |
| ProofPointTRAP.Incident.quarantine_results.status | String | The status of the result. |
| ProofPointTRAP.Incident.quarantine_results.recipientType | String | The recipient type. |
| ProofPointTRAP.Incident.quarantine_results.recipient | String | The recipient email address. |
| ProofPointTRAP.Incident.quarantine_results.messageId | String | The message ID. |
| ProofPointTRAP.Incident.quarantine_results.isRead | Boolean | Whether the message has been read. |
| ProofPointTRAP.Incident.quarantine_results.wasUndone | String | Whether the message was undone. |
| ProofPointTRAP.Incident.quarantine_results.details | String | The details about the result. |
| ProofPointTRAP.Incident.successful_quarantines | Number | The number of successful quarantines. |
| ProofPointTRAP.Incident.failed_quarantines | Number | The number of failed quarantines. |
| ProofPointTRAP.Incident.pending_quarantines | Number | The number of pending quarantines. |
| ProofPointTRAP.Incident.events.emails.body | String | The body of the email. |
| ProofPointTRAP.Incident.events.emails.body_type | String | The format of the body. |
| ProofPointTRAP.Incident.events.emails.headers | Unknown | The email headers. |
| ProofPointTRAP.Incident.events.emails.urls | Unknown | The list of URLs from the email. |
| ProofPoint.Incident.event_ids | Unknown | The list of IDs attached to the incident. |
proofpoint-tr-update-incident-comment
Adds comments to an existing Threat Response incident, by incident ID.
Base Command
proofpoint-tr-update-incident-comment
Input
| Argument Name | Description | Required |
|---|---|---|
| incident_id | The ID value of the incident to add the comment to (e.g. for incident INC-4000, the input for this argument should be 4000). | Required |
| details | The details of the comments. | Required |
| comments | The summary of the comments. | Required |
Context Output
| Path | Type | Description |
|---|---|---|
| ProofPointTRAP.IncidentComment.id | Number | The ID of the comment. |
| ProofPointTRAP.IncidentComment.incident_id | Number | The ID of the incident. |
| ProofPointTRAP.IncidentComment.response_id | Number | The ID of the response. |
| ProofPointTRAP.IncidentComment.user_id | String | The ID of the user. |
| ProofPointTRAP.IncidentComment.history_type | String | The history type. |
| ProofPointTRAP.IncidentComment.state_from | String | The state from of the incident. |
| ProofPointTRAP.IncidentComment.state_to | String | The state to of the incident. |
| ProofPointTRAP.IncidentComment.summary | String | The summary of the comments. |
| ProofPointTRAP.IncidentComment.detail | String | The details of the comment. |
| ProofPointTRAP.IncidentComment.created_at | Date | The date the incident was created. |
| ProofPointTRAP.IncidentComment.updated_at | Date | The date the incident was last updated. |
proofpoint-tr-add-user-to-incident
Assigns a user to an incident as a target or attacker.
Base Command
proofpoint-tr-add-user-to-incident
Input
| Argument Name | Description | Required |
|---|---|---|
| incident_id | The ID value of the incident to add the user to (e.g. for incident INC-4000, the input for this argument should be 4000). | Required |
| targets | The list of targets to add to the incident. | Required |
| attackers | The list of attackers to add to the incident. | Required |
Context Output
There is no context output for this command.
proofpoint-tr-ingest-alert
Ingest an alert into Threat Response.
Base Command
proofpoint-tr-ingest-alert
Input
| Argument Name | Description | Required |
|---|---|---|
| post_url_id | The POST URL of the JSON alert source. You can find it by navigating to Sources -> JSON event source -> POST URL. | Optional |
| json_version | The Threat Response JSON version. Possible values are: 2.0, 1.0. Default is 2.0. |
Required |
| attacker | An attacker object in JSON format : “{“attacker” : {…}}”. The attacker object must contain one of [“ip_address”, mac_address”, “host_name”, “url”, “user”] keys. You can also add the “port” key to the object. For more information, see Proofpoint TRAP documentation under “JSON Alert Source 2.0”. | Optional |
| classification | The alert classification shown as “Alert Type” in the TRAP UI. Possible values are: malware, policy-violation, vulnerability, network, spam, phish, command-and-control, data-match, authentication, system-behavior, impostor, reported-abuse, unknown. |
Optional |
| cnc_hosts | The Command and Control host information in JSON format : “{“cnc_hosts”: [{“host” : “-“, “port”: “-“}, …]}”. Note: Every item of the “cnc_hosts” list is in JSON format. For more information, see Proofpoint TRAP documentation under “JSON Alert Source 2.0”. |
Optional |
| detector | The threat detection tool such as Firewall and IPS/IDS systems (in the format: “{“detector” : {…}}”), which generated the original alert. To see all relevant JSON fields and for more information, see Proofpoint TRAP documentation under “JSON Alert Source 2.0”. | Optional |
| The email metadata related to the alert, in JSON format: “{“email”: {…}}”. To see all relevant JSON fields and for more information, see Proofpoint TRAP documentation under “JSON Alert Source 2.0”. | Optional | |
| forensics_hosts | The forensics host information in JSON format : “{“forensics_hosts”: [{“host” : “-“, “port”: “-“}…]}”. Note: Every item of the “forensics_hosts” list is in JSON format. For more information, see Proofpoint TRAP documentation under “JSON Alert Source 2.0”. |
Optional |
| link_attribute | The attribute to link alerts to. Possible values are: target_ip_address, target_hostname, target_machine_name, target_user, target_mac_address, attacker_ip_address, attacker_hostname, attacker_machine_name, attacker_user, attacker_mac_address, email_recipient, email_sender, email_subject, message_id, threat_filename, threat_filehash. |
Optional |
| severity | The severity of the alert. Possible values are: info, minor, moderate, major, critical, Informational, Low, Medium, High, Critical. |
Optional |
| summary | The alert summary. This argument will populate the Alert Details field. | Optional |
| target | The target host information in JSON format : “{“target”: {…}}”. To see all relevant JSON fields and for more information, see Proofpoint TRAP documentation under “JSON Alert Source 2.0”. | Optional |
| threat_info | The threat information in JSON format: “{“threat_info”: {…}}”. To see all relevant JSON fields and for more information, see Proofpoint TRAP documentation under “JSON Alert Source 2.0”. | Optional |
| custom_fields | A JSON object for collecting custom name-value pairs as part of the JSON alert sent to Threat Response, in the format: “{“custom_fields”: {..}}”. Although there is no limit to the number of custom fields, Proofpoint recommends keeping it to 10 or fewer fields. To see all relevant JSON fields and for more information, see Proofpoint TRAP documentation under “JSON Alert Source 2.0”. | Optional |
Context Output
There is no context output for this command.
proofpoint-tr-close-incident
Close an incident
Base Command
proofpoint-tr-close-incident
Input
| Argument Name | Description | Required |
|---|---|---|
| incident_id | The ID value of the incident to close. | Required |
| details | The details for the closure notes. | Required |
| summary | The summary for the closure notes. | Required |
Context Output
There is no context output for this command.
proofpoint-tr-verify-quarantine
Verify if an email has been quarantined.
Base Command
proofpoint-tr-verify-quarantine
Input
| Argument Name | Description | Required |
|---|---|---|
| message_id | The ID value of an email. | True |
| time | The creation time of the incident in the format YYYY-MM-DDTHH:MM:SSZ. For example: 2020-02-02T19:00:00Z. | True |
| recipient | The email recipient. | True |
| limit_quarantine_occurred_time | Whether or not to limit the results to include only quarantines that occurred within a limited time after alert creation. Automated quarantine actions for example typically occur within 120 seconds of alert firing. Manual actions executed by human may take longer. Default is True. | False |
| quarantine_limit | Only used if ‘limit_quarantine_occurred_time’ argument is set to true. Sets a limit on the quarantines retrieved to include only those where the time difference between alert time and quarantined time is less than the number of seconds specified. The time is in seconds. Default is 120. | False |
| fetch_delta | The time frame (in hours) used to identify the size of batches when retrieving the messages. e.g., 12. Default is 6. | False |
| check_exact_reception_time | If true, the command checks for quarantined emails with the exact reception time of the email. If false, the verification of the quarantined email only uses the message ID and the recipient email. Default is true. | False |
Context Output
| Path | Type | Description |
|---|---|---|
| ProofPointTRAP.Quarantine | String | The result of the quarantine. |
Command Example
!proofpoint-tr-verify-quarantine messageid=<message_id_example> time="2022-06-02T17:22:45Z" recipient=example@example.com
Context Example
{
"ProofPointTRAP": {
"Quarantine": [
{
"alert": {
"id": 1030,
"time": "2022-06-02T17:33:18Z"
},
"incident": {
"id": 265,
"time": "2022-06-02T17:33:18Z"
},
"quarantine": {
"alertSource": "Admin Portal",
"details": "Success",
"endTime": "2022-06-02T17:33:37.926Z",
"isRead": "false",
"messageId": "message_id_example",
"recipient": "example@example.com",
"recipientType": "Original Recipient",
"startTime": "2022-06-02T17:33:20.352Z",
"status": "successful",
"wasUndone": "false"
}
},
{
"alert": {
"id": 1030,
"time": "2022-06-02T17:33:18Z"
},
"incident": {
"id": 265,
"time": "2022-06-02T17:33:18Z"
},
"quarantine": {
"alertSource": "Admin Portal",
"details": "Success",
"endTime": "2022-06-02T17:33:37.321Z",
"isRead": "false",
"messageId": "message_id_example",
"recipient": "example@example.com",
"recipientType": "Original Recipient",
"startTime": "2022-06-02T17:33:20.283Z",
"status": "successful",
"wasUndone": "false"
}
}
]
}
}
Configuration parameters
url— Server URL (e.g. https://192.168.0.1) (required)credentials—apikey— API Keyinsecure— Trust any certificate (not secure)proxy— Use system proxy settingsisFetch— Fetch incidentsincidentType— Incident typeincidentFetchInterval— Incidents Fetch Intervalfirst_fetch— First fetch timestamp (<number> <time unit>, e.g., 12 hours, 7 days)fetch_limit— Fetch limit - maximum number of incidents per fetchfetch_delta— Fetch delta - The delta time in each batch. e.g. 1 hour, 3 minutes.states— Fetch incident with specific states.event_sources— Fetch incidents with specific event sources. Can be a list of comma separated values.abuse_disposition— Fetch incidents with specific 'Abuse Disposition' values. Can be a list of comma separated values.post_url_id— POST URL of the JSON alert source.
Commands (15)
-
proofpoint-tr-add-to-listAdds a member to the specified list.
-
proofpoint-tr-add-user-to-incidentAssigns a user to an incident as a target or attacker.
-
proofpoint-tr-block-domainAdds the supplied domains to the specified block list.
-
proofpoint-tr-block-hashAdds the supplied file hashes to the specified file hash block list.
-
proofpoint-tr-block-ipAdds the supplied IP addresses to the specified IP block list.
-
proofpoint-tr-block-urlAdds the supplied URLs to the specified URL block list.
-
proofpoint-tr-close-incidentClose a specified incident.
-
proofpoint-tr-delete-indicatorDeletes an indicator from the specified list.
-
proofpoint-tr-get-incidentRetrieves incident metadata from Threat Response.
-
proofpoint-tr-get-listGets items for the specified list.
-
proofpoint-tr-ingest-alertIngest an alert into Threat Response.
-
proofpoint-tr-list-incidentsRetrieves all incident metadata from Threat Response by specifying filter criteria such as the state of the incident or time of closure.
-
proofpoint-tr-search-indicatorReturns indicators from the specified list, according to the defined filter.
-
proofpoint-tr-update-incident-commentAdds comments to an existing Threat Response incident, by incident ID.
-
proofpoint-tr-verify-quarantineVerify if an email has been quarantined.
import json from datetime import date, timedelta import dateparser import demistomock as demisto # noqa: F401 import requests import urllib3 from CommonServerPython import * # noqa: F401 urllib3.disable_warnings() """ GLOBAL VARS """ TIME_FORMAT = "%Y-%m-%dT%H:%M:%SZ" BASE_URL = demisto.params().get("url") if BASE_URL and BASE_URL[-1] != "/": BASE_URL += "/" API_KEY = demisto.params().get("credentials", {}).get("password") or demisto.params().get("apikey") VERIFY_CERTIFICATE = not demisto.params().get("insecure") # How many time before the first fetch to retrieve incidents FIRST_FETCH, _ = parse_date_range(demisto.params().get("first_fetch", "12 hours") or "12 hours", date_format=TIME_FORMAT) """ COMMAND FUNCTIONS """ def get_list(list_id): fullurl = BASE_URL + f"api/lists/{list_id}/members.json" res = requests.get(fullurl, headers={"Content-Type": "application/json", "Authorization": API_KEY}, verify=VERIFY_CERTIFICATE) if res.status_code < 200 or res.status_code >= 300: return_error(f"Get list failed. URL: {fullurl}, StatusCode: {res.status_code}") return res.json() def get_list_command(): """Retrieves all indicators of a the given list ID in Threat Response""" list_id = demisto.args().get("list-id") list_items = get_list(list_id) demisto.results({"list": list_items}) def add_to_list(list_id, indicator, comment, expiration): fullurl = BASE_URL + f"api/lists/{list_id}/members.json" indicator = {"member": indicator} if comment: indicator["description"] = comment if expiration: indicator["expiration"] = expiration res = requests.post(fullurl, headers={"Authorization": API_KEY}, verify=VERIFY_CERTIFICATE, json=indicator) if res.status_code < 200 or res.status_code >= 300: return_error(f"Add to list failed. URL: {fullurl}, Request Body: {json.dumps(indicator)}") return res.json() def add_to_list_command(): """Adds given indicators to the given list ID in Threat Response""" list_id = demisto.args().get("list-id") indicators = argToList(demisto.args().get("indicator")) comment = demisto.args().get("comment") expiration = demisto.args().get("expiration") message = "" for indicator in indicators: add_to_list(list_id, indicator, comment, expiration) message += f"{indicator} added successfully to {list_id}\n" demisto.results(message) def block_ip_command(): """Adds given IPs to the relevant blacklist in Threat Response""" list_id = demisto.params().get("blacklist_ip", demisto.args().get("blacklist_ip")) ips = argToList(demisto.args().get("ip")) expiration = demisto.args().get("expiration") message = "" for ip in ips: add_to_list(list_id, ip, None, expiration) message += f"{ip} added successfully to block_ip list\n" demisto.results(message) def block_domain_command(): """Adds given domains to the relevant blacklist in Threat Response""" list_id = demisto.params().get("blacklist_domain", demisto.args().get("blacklist_domain")) domains = argToList(demisto.args().get("domain")) expiration = demisto.args().get("expiration") message = "" for domain in domains: add_to_list(list_id, domain, None, expiration) message += f"{domain} added successfully to block_domain list\n" demisto.results(message) def block_url_command(): """Adds given URLs to the relevant blacklist in Threat Response""" list_id = demisto.params().get("blacklist_url", demisto.args().get("blacklist_url")) urls = argToList(demisto.args().get("url")) expiration = demisto.args().get("expiration") message = "" for url in urls: add_to_list(list_id, url, None, expiration) message += f"{url} added successfully to block_url list\n" demisto.results(message) def block_hash_command(): """Adds given hashes to the relevant blacklist in Threat Response""" list_id = demisto.params().get("blacklist_hash", demisto.args().get("blacklist_hash")) hashes = argToList(demisto.args().get("hash")) expiration = demisto.args().get("expiration") message = "" for h in hashes: add_to_list(list_id, h, None, expiration) message += f"{h} added successfully to block_hash list\n" demisto.results(message) def search_indicators(list_id, indicator_filter): list_indicators = get_list(list_id) found_items = [] for item in list_indicators: item_indicator = demisto.get(item, "host.host") if item_indicator and indicator_filter in item_indicator: found_items.append(item) return found_items def search_indicator_command(): """Retrieves indicators of a list, using a filter""" list_id = demisto.args().get("list-id") indicator_filter = demisto.args().get("filter") found = search_indicators(list_id, indicator_filter) demisto.results({"indicators": found}) def delete_indicator(list_id, indicator_filter): indicator = search_indicators(list_id, indicator_filter) if len(indicator) == 0: return_error(f"{indicator_filter} not exists in {list_id}") indicator_id = indicator.get("id") # pylint: disable=E1101 fullurl = BASE_URL + f"api/lists/{list_id}/members/{indicator_id}.json" res = requests.delete(fullurl, headers={"Authorization": API_KEY}, verify=VERIFY_CERTIFICATE) if res.status_code < 200 or res.status_code >= 300: return_error(f"Delete indicator failed. URL: {fullurl}, StatusCode: {res.status_code}") def delete_indicator_command(): """Deletes an indicator from a list""" list_id = demisto.args().get("list-id") indicator = demisto.args().get("indicator") delete_indicator(list_id, indicator) demisto.results(f"{list_id} deleted successfully from list {indicator}") def test(): """Perform API call to check that the API is accessible. Returns: 'ok' if test passed, anything else will fail the test. """ integration_params = demisto.params() if integration_params.get("isFetch") and not integration_params.get("states"): raise DemistoException("Missing argument - You must provide at least one incident state.") get_incidents_request({"created_after": date.today(), "state": "open"}) demisto.results("ok") # TRAP API def create_incident_field_context(incident): """Parses the 'incident_fields' entry of the incident and returns it Args: incident (dict): The incident to parse Returns: list. The parsed incident fields list """ incident_field_values = {} for incident_field in incident.get("incident_field_values", []): incident_field_values[incident_field["name"].replace(" ", "_")] = incident_field["value"] return incident_field_values def get_emails_context(event): """Returns the context of the emails in the event Args: event (dict): The event to parse the emails from Returns: list. The parsed emails list from the event """ emails_context = [] for email in event.get("emails", []): email_obj = { "sender": email.get("sender", {}).get("email"), "recipient": email.get("recipient", {}).get("email"), "subject": email.get("subject"), "message_id": email.get("messageId"), "body": email.get("body"), "body_type": email.get("bodyType"), "headers": email.get("headers"), "urls": email.get("urls"), "sender_vap": email.get("sender", {}).get("vap"), "recipient_vap": email.get("recipient", {}).get("vap"), "attachments": email.get("attachments"), } message_delivery_time = email.get("messageDeliveryTime", {}) if message_delivery_time and isinstance(message_delivery_time, dict): email_obj["message_delivery_time"] = message_delivery_time.get("millis") elif message_delivery_time and isinstance(message_delivery_time, str): email_obj["message_delivery_time"] = message_delivery_time emails_context.append(assign_params(**email_obj)) return emails_context def create_incidents_context(incidents_list): """Parses the incidents list and returns the incidents context Args: incidents_list (list): The incidents list to parse Returns: list. The context created from the incidents list """ context = list(incidents_list) for incident in context: incident["incident_field_values"] = create_incident_field_context(incident) if incident.get("events"): for event in incident["events"]: event["emails"] = get_emails_context(event) return context def create_incidents_human_readable(human_readable_message, incidents_list): """Creates the human readable entry for incidents Args: human_readable_message (str): The title of the human readable table incidents_list (list): The incidents list to insert to the table Returns: str. The incidents human readable in markdown format """ human_readable = [] human_readable_headers = [ "ID", "Created At", "Type", "Summary", "Score", "Event Count", "Assignee", "Successful Quarantines", "Failed Quarantines", "Pending Quarantines", ] for incident in incidents_list: human_readable.append( { "Created At": incident.get("created_at"), "ID": incident.get("id"), "Type": incident.get("type"), "Summary": incident.get("summary"), "Score": incident.get("score"), "Event Count": incident.get("event_count"), "Assignee": incident.get("assignee"), "Successful Quarantines": incident.get("successful_quarantine"), "Failed Quarantines": incident.get("failed_quarantines"), "Pending Quarantines": incident.get("pending_quarantines"), } ) return tableToMarkdown(human_readable_message, human_readable, human_readable_headers, removeNull=True) def list_incidents_command(): """Retrieves incidents from ProofPoint API""" args = demisto.args() limit = int(args.pop("limit")) incidents_list = get_incidents_request(args) incidents_list = incidents_list[:limit] human_readable = create_incidents_human_readable("List Incidents Results:", incidents_list) context = create_incidents_context(incidents_list) return_outputs(human_readable, {"ProofPointTRAP.Incident(val.id === obj.id)": context}, incidents_list) def get_incident_command(): """ Retrieves a single incident from ProofPoint API """ args = demisto.args() incident_id = args.pop("incident_id") expand_events = args.get("expand_events") fullurl = BASE_URL + f"api/incidents/{incident_id}.json" incident_data = requests.get( fullurl, headers={"Content-Type": "application/json", "Authorization": API_KEY}, params={ "expand_events": expand_events, }, verify=VERIFY_CERTIFICATE, ) if incident_data.status_code < 200 or incident_data.status_code >= 300: return_error(f"Get incident failed. URL: {fullurl}, StatusCode: {incident_data.status_code}") incident_data = incident_data.json() human_readable = create_incidents_human_readable("Incident Results:", [incident_data]) context = create_incidents_context([incident_data]) return_outputs(human_readable, {"ProofPointTRAP.Incident(val.id === obj.id)": context}, incident_data) def pass_sources_list_filter(incident, sources_list): """Checks whether the event sources of the incident contains at least one of the sources in the sources list. Args: incident (dict): The incident to check sources_list (list): The list of sources from the customer Returns: bool. Whether the incident has passed the filter or not """ if len(sources_list) == 0: return True return any(source in incident.get("event_sources") for source in sources_list) def pass_abuse_disposition_filter(incident, abuse_disposition_values): """Checks whether the incident's 'Abuse Disposition' value is in the abuse_disposition_values list. Args: incident (dict): The incident to check abuse_disposition_values (list): The list of relevant values from the customer Returns: bool. Whether the incident has passed the filter or not """ if len(abuse_disposition_values) == 0: return True for incident_field in incident.get("incident_field_values", []): if incident_field["name"] == "Abuse Disposition" and incident_field["value"] in abuse_disposition_values: return True return False def filter_incidents(incidents_list): """Filters the incidents list by 'abuse disposition' and 'source list' values Args: incidents_list (list): The incidents list to filter Returns: list. The filtered incidents list """ filtered_incidents_list = [] params = demisto.params() sources_list = argToList(params.get("event_sources")) abuse_disposition_values = argToList(params.get("abuse_disposition")) if not sources_list and not abuse_disposition_values: return incidents_list for incident in incidents_list: if pass_sources_list_filter(incident, sources_list) and pass_abuse_disposition_filter(incident, abuse_disposition_values): filtered_incidents_list.append(incident) return filtered_incidents_list def get_incidents_request(params): """Perform an API request to get incidents from ProofPoint. Args: params(dict): The params of the request Returns: list. The incidents returned from the API call """ fullurl = BASE_URL + "api/incidents" incidents_list = requests.get( fullurl, headers={"Content-Type": "application/json", "Authorization": API_KEY}, params=params, verify=VERIFY_CERTIFICATE ) if incidents_list.status_code < 200 or incidents_list.status_code >= 300: if incidents_list.status_code == 502 or incidents_list.status_code == 504: return_error( "The operation failed. There is a possibility you are trying to get too many incidents.\n" "You may consider adding a filter argument to the command.\n" f"URL: {fullurl}, StatusCode: {incidents_list.status_code}" ) else: return_error(f"The operation failed. URL: {fullurl}, StatusCode: {incidents_list.status_code}") return incidents_list.json() def get_time_delta(fetch_delta): """Gets the time delta from a string that is combined with a number and a string of (minute/hour) Args: fetch_delta(str): The fetch delta param. Returns: The time delta. """ fetch_delta_split = fetch_delta.strip().split(" ") if len(fetch_delta_split) != 2: raise Exception("The fetch_delta is invalid. Please make sure to insert both the number and the unit of the fetch delta.") unit = fetch_delta_split[1].lower() number = int(fetch_delta_split[0]) if unit not in [ "minute", "minutes", "hour", "hours", ]: raise Exception('The unit of fetch_delta is invalid. Possible values are "minutes" or "hours".') if "hour" in unit: time_delta = timedelta(hours=number) # batch by hours else: time_delta = timedelta(minutes=number) # batch by minutes return time_delta def get_new_incidents(request_params, last_fetched_id): """Perform an API request to get incidents from ProofPoint , filters then according to params, order them and return only the new incidnts. As the api does not return the results in an specific order, we query the api on specific time frames using created_before and created_after using the fetch delta parameter. Args: request_params(dict): The params of the request last_fetched_id(int): The ID of the last incident that was fetched in the previous fetch. Returns: list. The incidents returned from after the necessary actions. """ incidents = get_incidents_request(request_params) filtered_incidents_list = filter_incidents(incidents) ordered_incidents = sorted(filtered_incidents_list, key=lambda k: (k["created_at"], k["id"])) return list(filter(lambda incident: int(incident.get("id")) > last_fetched_id, ordered_incidents)) def get_incidents_batch_by_time_request(params): """Perform an API request to get incidents from ProofPoint in batches to prevent a timeout. As the api does not return the results in an specific order, we query the api on specific time frames using created_before and created_after using the fetch delta parameter. Args: params(dict): The params of the request Returns: list. The incidents returned from the API call """ incidents_list = [] # type:list fetch_delta = params.get("fetch_delta", "6 hours") fetch_limit = int(params.get("fetch_limit", "50")) last_fetched_id = int(params.get("last_fetched_id", "0")) current_time = datetime.now() time_delta = get_time_delta(fetch_delta) created_after = datetime.strptime(params.get("created_after"), TIME_FORMAT) created_before = created_after + time_delta request_params = { "state": params.get("state"), "created_after": created_after.isoformat().split(".")[0] + "Z", "created_before": created_before.isoformat().split(".")[0] + "Z", } if message_id := params.get("message_id"): # used in search quarantine request_params["message_id"] = message_id # while loop relevant for fetching old incidents while created_before < current_time and len(incidents_list) < fetch_limit: demisto.debug( "PTR: Entered the batch loop , with fetch_limit {} and incidents list {} and incident length {} " "with created_after {} and created_before {}.".format( str(fetch_limit), str([incident.get("id") for incident in incidents_list]), str(len(incidents_list)), str(request_params["created_after"]), str(request_params["created_before"]), ) ) new_incidents = get_new_incidents(request_params, last_fetched_id) incidents_list.extend(new_incidents) # advancing fetch time by given fetch delta time created_after = created_before created_before = created_before + time_delta # updating params according to the new times request_params["created_after"] = created_after.isoformat().split(".")[0] + "Z" request_params["created_before"] = created_before.isoformat().split(".")[0] + "Z" demisto.debug(f"PTR: End of the current batch loop with {len(incidents_list)!s} incidents") # fetching the last batch when created_before is bigger then current time = fetching new incidents if len(incidents_list) < fetch_limit: # fetching the last batch request_params["created_before"] = current_time.isoformat().split(".")[0] + "Z" new_incidents = get_new_incidents(request_params, last_fetched_id) incidents_list.extend(new_incidents) demisto.debug( "PTR: Finished the last batch, with fetch_limit {} and incidents list {} and incident length {}".format( str(fetch_limit), str([incident.get("id") for incident in incidents_list]), str(len(incidents_list)) ) ) incidents_list_limit = incidents_list[:fetch_limit] return incidents_list_limit def fetch_incidents_command(): """ Fetches incidents from the ProofPoint API. """ integration_params = demisto.params() last_fetch = demisto.getLastRun().get("last_fetch", {}) last_fetched_id = demisto.getLastRun().get("last_fetched_incident_id", {}) fetch_delta = integration_params.get("fetch_delta", "6 hours") fetch_limit = integration_params.get("fetch_limit", "50") incidents_states = integration_params.get("states") for state in incidents_states: if not last_fetch.get(state): last_fetch[state] = FIRST_FETCH for state in incidents_states: if not last_fetched_id.get(state): last_fetched_id[state] = "0" incidents = [] for state in incidents_states: request_params = { "created_after": last_fetch[state], "last_fetched_id": last_fetched_id[state], "fetch_delta": fetch_delta, "state": state, "fetch_limit": fetch_limit, } id = last_fetched_id[state] incidents_list = get_incidents_batch_by_time_request(request_params) for incident in incidents_list: id = incident.get("id") inc = {"name": f"ProofPoint_TRAP - ID {id}", "rawJSON": json.dumps(incident), "occurred": incident["created_at"]} incidents.append(inc) if incidents: last_fetch_time = incidents[-1]["occurred"] last_fetch[state] = (datetime.strptime(last_fetch_time, TIME_FORMAT) - timedelta(minutes=1)).isoformat().split(".")[ 0 ] + "Z" last_fetched_id[state] = id demisto.debug( f"PTR: End of current fetch function with last_fetch {str(last_fetch)} and last_fetched_id {str(last_fetched_id)}" ) demisto.setLastRun({"last_fetch": last_fetch}) demisto.setLastRun({"last_fetched_incident_id": last_fetched_id}) demisto.info(f"extracted {len(incidents)} incidents") demisto.incidents(incidents) def create_add_comment_human_readable(incident): """Creates the human readable entry for the 'add_comment_to_incident' command Args: incident (dict): The incident to parse Returns: str. The command human readable in markdown format """ human_readable = [] human_readable_headers = ["Incident ID", "Created At", "Details", "Comments Summary", "Action ID"] incident_id = incident.get("incident_id") human_readable.append( { "Created At": incident.get("created_at"), "Incident ID": incident_id, "Details": incident.get("detail"), "Comments Summary": incident.get("summary"), "Action ID": incident.get("id"), } ) return tableToMarkdown( f"Comments added successfully to incident:{incident_id}", human_readable, human_readable_headers, removeNull=True ) def add_comment_to_incident_command(): """ Adds comments to an incident by incident ID """ args = demisto.args() incident_id = args.get("incident_id") comments_to_add = args.get("comments") details = args.get("details") request_body = {"summary": comments_to_add, "detail": details} fullurl = BASE_URL + f"api/incidents/{incident_id}/comments.json" incident_data = requests.post( fullurl, headers={"Content-Type": "application/json", "Authorization": API_KEY}, json=request_body, verify=VERIFY_CERTIFICATE, ) if incident_data.status_code < 200 or incident_data.status_code >= 300: return_error(f"Add comment to incident command failed. URL: {fullurl}, StatusCode: {incident_data.status_code}") incident_data = incident_data.json() human_readable = create_add_comment_human_readable(incident_data) return_outputs( human_readable, {"ProofPointTRAP.IncidentComment(val.incident_id === obj.incident_id)": incident_data}, incident_data ) def add_user_to_incident_command(): """ Adds user to an incident by incident ID """ args = demisto.args() incident_id = args.get("incident_id") attackers = argToList(args.get("attackers")) targets = argToList(args.get("targets")) request_body = {"targets": targets, "attackers": attackers} fullurl = BASE_URL + "api/incidents/{incident_id}/users.json" incident_data = requests.post( fullurl, headers={"Content-Type": "application/json", "Authorization": API_KEY}, json=request_body, verify=VERIFY_CERTIFICATE, ) if incident_data.status_code < 200 or incident_data.status_code >= 300: return_error(f"Add comment to incident command failed. URL: {fullurl}, StatusCode: {incident_data.status_code}") return_outputs(f"The user was added successfully to incident {incident_id}", {}, {}) def parse_json_argument(argument_string_value, argument_name): parsed_arg = {} try: parsed_arg = json.loads(argument_string_value) except ValueError as error: return_error(f"The '{argument_name}' argument is not a valid json. Error: {error}") if not parsed_arg.get(argument_name): return_error(f"The '{argument_name}' json argument should start with a key named '{argument_name}'") return parsed_arg def prepare_ingest_alert_request_body(args): json_arguments = ["attacker", "cnc_host", "detector", "email", "forensics_hosts", "target", "threat_info", "custom_fields"] request_body = {} # type: dict for argument_name, argument_value in args.items(): if argument_name in json_arguments: parsed_argument = parse_json_argument(argument_value, argument_name) request_body.update(parsed_argument) else: request_body[argument_name] = argument_value return request_body def ingest_alert_command(): """ Ingest an alert into Threat Response. """ args = demisto.args() json_source_id = args.pop("post_url_id", demisto.params().get("post_url_id")) if not json_source_id: return_error( "To ingest alert into TRAP, you mast specify a post_url_id,either as an argument or as an integration parameter." ) request_body = prepare_ingest_alert_request_body(assign_params(**args)) fullurl = BASE_URL + f"threat/json_event/events/{json_source_id}" alert_data = requests.post( fullurl, headers={"Content-Type": "application/json"}, json=request_body, verify=VERIFY_CERTIFICATE ) if alert_data.status_code < 200 or alert_data.status_code >= 300: return_error(f"Failed to ingest the alert into TRAP. URL: {fullurl}, StatusCode: {alert_data.status_code}") return_outputs("The alert was successfully ingested to TRAP", {}, {}) def close_incident_command(): args = demisto.args() incident_id = args.get("incident_id") details = args.get("details") summary = args.get("summary") request_body = {"summary": summary, "detail": details} fullurl = BASE_URL + f"api/incidents/{incident_id}/close.json" incident_data = requests.post( fullurl, headers={"Content-Type": "application/json", "Authorization": API_KEY}, json=request_body, verify=VERIFY_CERTIFICATE, ) if incident_data.status_code < 200 or incident_data.status_code >= 300: return_error(f"Incident closure failed. URL: {fullurl}, StatusCode: {incident_data.status_code}") return_outputs(f"The incident {incident_id} was successfully closed", {}, {}) def search_quarantine(): args = demisto.args() arg_time = dateparser.parse(args.get("time")) emailTAPtime = 0 if isinstance(arg_time, datetime): emailTAPtime = int(arg_time.timestamp()) else: return_error("Timestamp was bad") lstAlert = [] mid = args.get("message_id") recipient = args.get("recipient") limit_quarantine_occurred_time = argToBoolean(args.get("limit_quarantine_occurred_time", "True")) quarantine_limit = arg_to_number(args.get("quarantine_limit", 120)) fetch_delta = arg_to_number(args.get("fetch_delta", 6)) check_exact_reception_time = argToBoolean(args.get("check_exact_reception_time", True)) request_params = { "created_after": datetime.strftime(arg_time - get_time_delta("1 hour"), TIME_FORMAT), # for safety "fetch_delta": f"{fetch_delta} hours", "fetch_limit": "50", "message_id": mid, } incidents_list = get_incidents_batch_by_time_request(request_params) found = {"email": False, "mid": False, "quarantine": False} resQ = [] # Collecting emails inside alert to find those with same recipient and messageId for incident in incidents_list: for alert in incident.get("events"): demisto.debug(f'New alert being processed with Alertid = {alert.get("id")}') for email in alert.get("emails"): demisto.debug(f'New email being processed with messageid {email.get("messageId")}') message_delivery_time = email.get("messageDeliveryTime", {}) demisto.debug(f"PTR: Got {message_delivery_time=} with type {type(message_delivery_time)}.") if message_delivery_time and isinstance(message_delivery_time, dict): message_delivery_time = message_delivery_time.get("millis") elif message_delivery_time and isinstance(message_delivery_time, str): message_delivery_time = dateparser.parse(message_delivery_time) if message_delivery_time: message_delivery_time = int(message_delivery_time.timestamp() * 1000) else: demisto.info(f'PTR: Could not parse time of incident {incident.get("id")}, got {message_delivery_time=}') continue if email.get("messageId") == mid and email.get("recipient").get("email") == recipient and message_delivery_time: found["mid"] = True demisto.debug("PTR: Found the email, adding the alert") emailTRAPtimestamp = int(message_delivery_time / 1000) if emailTAPtime == emailTRAPtimestamp or not check_exact_reception_time: demisto.debug(f'PTR: Adding the alert with id {alert.get("id")}') found["email"] = True lstAlert.append( { "incidentid": incident.get("id"), "alertid": alert.get("id"), "alerttime": alert.get("received"), "incidenttime": incident.get("created_at"), "messageId": mid, "quarantine_results": incident.get("quarantine_results"), } ) else: demisto.debug( f'PTR: Alert id {alert.get("id")} found but not added to lstAlert list as ' f'{emailTAPtime=} did not match {emailTRAPtimestamp=}' ) else: demisto.debug( f'PTR: skipped message with ID {email.get("messageId")} and recipient' f' {email.get("recipient").get("email")}. As it did not match {mid=} and' f' recipient={email.get("recipient").get("email")}' ) quarantineFoundcpt = 0 # Go though the alert list, and check the quarantine results: for alert in lstAlert: for quarantine in alert.get("quarantine_results"): if quarantine.get("messageId") == mid and quarantine.get("recipient") == recipient: found["quarantine"] = True tsquarantine = dateparser.parse(quarantine.get("startTime")) tsalert = dateparser.parse(alert.get("alerttime")) if isinstance(tsquarantine, datetime) and isinstance(tsalert, datetime): diff = (tsquarantine - tsalert).total_seconds() # Append alerts if limit_quarantine_occurred_time=False # else checks diff is less then quarantine_limit if (not limit_quarantine_occurred_time) or (quarantine_limit and 0 < diff < quarantine_limit): resQ.append( { "quarantine": quarantine, "alert": {"id": alert.get("alertid"), "time": alert.get("alerttime")}, "incident": {"id": alert.get("incidentid"), "time": alert.get("incidenttime")}, } ) else: quarantineFoundcpt += 1 demisto.debug( f'PTR: Quarantine found for {quarantine.get("messageId")} but not returned as it did not meet filter' f' requirements. limit_quarantine_occurred_time = {limit_quarantine_occurred_time} with type ' f'{type(limit_quarantine_occurred_time)}. diff = {diff}, quarantine_limit = {quarantine_limit}' ) else: demisto.debug(f"PTR: Failed to parse timestamp of incident: {alert=} {quarantine=}.") if quarantineFoundcpt > 0: return CommandResults( readable_output=( f"{mid} Message ID matches to {quarantineFoundcpt} emails quarantined, but time between alert " f"received and the quarantine starting exceeded the quarantine_limit provided" ) ) if not found["mid"]: return CommandResults(readable_output=f"Message ID {mid} not found in TRAP incidents") midtxt = f"{mid} Message ID found in TRAP alerts," if not found["email"]: return CommandResults( readable_output=f"{midtxt} but timestamp between email delivery time and time given as argument doesn't match" ) elif not found["quarantine"]: demisto.debug("PTR: " + "\n".join([json.dumps(alt, indent=4) for alt in lstAlert])) return CommandResults(f"{midtxt} but not in the quarantine list meaning that email has not be quarantined.") return CommandResults( outputs_prefix="ProofPointTRAP.Quarantine", outputs=resQ, readable_output=tableToMarkdown("Quarantine Result", resQ), raw_response=resQ, ) """ EXECUTION CODE """ def main(): handle_proxy(demisto.params().get("proxy")) command = demisto.command() demisto.info(f"Command being called is {command}") if command == "test-module": test() elif command == "fetch-incidents": fetch_incidents_command() elif command == "proofpoint-tr-get-list": get_list_command() elif command == "proofpoint-tr-add-to-list": add_to_list_command() elif command == "proofpoint-tr-block-ip": block_ip_command() elif command == "proofpoint-tr-block-domain": block_domain_command() elif command == "proofpoint-tr-block-url": block_url_command() elif command == "proofpoint-tr-block-hash": block_hash_command() elif command == "proofpoint-tr-delete-indicator": delete_indicator_command() elif command == "proofpoint-tr-search-indicator": search_indicator_command() elif command == "proofpoint-tr-list-incidents": list_incidents_command() elif command == "proofpoint-tr-get-incident": get_incident_command() elif command == "proofpoint-tr-update-incident-comment": add_comment_to_incident_command() elif command == "proofpoint-tr-add-user-to-incident": add_user_to_incident_command() elif command == "proofpoint-tr-ingest-alert": ingest_alert_command() elif command == "proofpoint-tr-close-incident": close_incident_command() elif command == "proofpoint-tr-verify-quarantine": return_results(search_quarantine()) if __name__ == "__builtin__" or __name__ == "builtins": main()