Signal Sciences WAF
Protect your web application using Signal Sciences.
Network Security · Signal Sciences WAF
Details
| ID | Signal Sciences WAF |
|---|---|
| Provider | Fastly |
| 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 Signal Sciences next-gen web application firewall to increase security and maintain reliability.
Configure Signal Sciences WAF on Cortex XSOAR
- Navigate to Settings > Integrations > Servers & Services.
- Search for Signal Sciences WAF.
- Click Add instance to create and configure a new integration instance.
- Name: a textual name for the integration instance.
- Token
- Corporation Name (should match the pattern [0-9a-z_.-]+)
- Fetch incidents
- Incident type
- Fetch Interval (in minutes)
- CSV list of sites to fetch from. If no sites are specified, events from all corporation’s sites will be fetched.
- Click Test to validate the URLs, token, and connection.
Commands
You can execute these commands from the Cortex XSOAR 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.
- Get a site’s allow list: sigsci-get-whitelist
- Get a site’s block list: sigsci-get-blacklist
- Add an IP address to an allow list: sigsci-whitelist-add-ip
- Add an IP address to a block list: sigsci-blacklist-add-ip
- Remove an IP address from an allow list: sigsci-whitelist-remove-ip
- Remove an IP address from a block list: sigsci-blacklist-remove-ip
- Get all site names: sigsci-get-sites
- Create a list for a site: sigsci-create-site-list
- Get information for a site list: sigsci-get-site-list
- Delete a site list: sigsci-delete-site-list
- Update a site list: sigsci-update-site-list
- Add an alert to a site: sigsci-add-alert
- Get information for an alert: sigsci-get-alert
- Delete an alert from a site: sigsci-delete-alert
- Update attributes for an alert: sigsci-update-alert
- Get all alerts for a site: sigsci-get-all-alerts
- Get all lists for a site: sigsci-get-all-site-lists
- Create a corp list: sigsci-create-corp-list
- Get information for a corp list: sigsci-get-corp-list
- Delete a corp list: sigsci-delete-corp-list
- Update a corp list: sigsci-update-corp-list
- Get information for all lists of a corp: sigsci-get-all-corp-lists
- Get a list of events: sigsci-fetch-events
- Get an event by event ID: sigsci-get-event-by-id
- Expire an event: sigsci-expire-event
- Get requests for a site: sigsci-get-requests
- Get a request by request ID: sigsci-get-request-by-id
1. Get a site’s allow list
Fetches a site’s allow list, which resides on the Signal Sciences’ platform.
Base Command
sigsci-get-whitelist
Input
| Argument Name | Description | Required |
|---|---|---|
| siteName | The site that holds the allow list you want to get. | Required |
Context Output
| Path | Type | Description |
|---|---|---|
| SigSciences.Corp.Site.Whitelist.ID | string | ID for this particular entry. |
| SigSciences.Corp.Site.Whitelist.Source | string | IP Address present in the allow list. |
| SigSciences.Corp.Site.Whitelist.ExpiryDate | date | Expiration Timestamp. |
| SigSciences.Corp.Site.Whitelist.Note | string | Note associated with the tag. |
| SigSciences.Corp.Site.Whitelist.CreatedDate | date | The created date timestamp |
| SigSciences.Corp.Site.Whitelist.CreatedBy | string | The user who added this source. |
Command Example
!sigsci-get-whitelist siteName=demisto
Context Example
{
"SigSciences.Corp.Site.Whitelist": [
{
"ExpiryDate": "",
"Note": "docdoc",
"Source": "9.7.9.7",
"CreatedBy": "user@demisto.com",
"CreatedDate": "2019-03-28T09:52:47Z",
"ID": "5c9c996fc7213901971d5679"
}
]
}
Human Readable Output
Signal Sciences - Whitelist
Number of IPs in the allow list 1
| Source | Note | Created Date | Created By |
|---|---|---|---|
| 9.7.9.7 | docdoc | 2019-03-28T09:52:47Z | user@demisto.com |
2. Get a site’s blacklist: sigsci-get-blacklist
Fetches a site’s block list, which resides on the Signal Sciences’ platform.
Base Command
sigsci-get-blacklist
Input
| Argument Name | Description | Required |
|---|---|---|
| siteName | The site that holds the block list you wish to get | Required |
Context Output
| Path | Type | Description |
|---|---|---|
| SigSciences.Corp.Site.Blacklist.ID | string | The ID for this entry. |
| SigSciences.Corp.Site.Blacklist.Source | string | The IP address on the blacklist. |
| SigSciences.Corp.Site.Blacklist.ExpiryDate | date | The expiration timestamp. |
| SigSciences.Corp.Site.Blacklist.Note | string | The note associated with the tag. |
| SigSciences.Corp.Site.Blacklist.CreatedDate | date | The created date timestamp. |
| SigSciences.Corp.Site.Blacklist.CreatedBy | string | The user who added this source. |
Command Example
!sigsci-get-blacklist siteName=demisto
Context Example
{
"SigSciences.Corp.Site.Blacklist": [
{
"ExpiryDate": "",
"Note": "docdoc",
"Source": "5.7.5.7",
"CreatedBy": "user@demisto.com",
"CreatedDate": "2019-03-28T09:52:49Z",
"ID": "5c9c9971719dcc0198a38a5b"
}
]
}
Human Readable Output
Signal Sciences - Blacklist
Number of IPs in the block list 1
| Source | Note | Created Date | Created By |
|---|---|---|---|
| 5.7.5.7 | docdoc | 2019-03-28T09:52:49Z | user@demisto.com |
3. Add an IP address to an allow list: sigsci-whitelist-add-ip
Adds an IP address to a site’s allow list, which resides the Signal Sciences’ platform.
Base Command
sigsci-whitelist-add-ip
Input
| Argument Name | Description | Required |
|---|---|---|
| siteName | The site that holds the allow list you want to add an IP address to. | Required |
| ip | The IP address to add to the site’s allow list in CSV format. | Required |
| note | The note associated with the tag. | Required |
| expires | The datetime for the IP address to removed from the site’s allow list (in RFC3339 format). To keep the IP address on the site’s allow list indefinitely, do not specify this argument. | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| SigSciences.Corp.Site.Whitelist.Source | string | The IP address on the allow list. |
| SigSciences.Corp.Site.Whitelist.Note | string | The note associated with the tag. |
| SigSciences.Corp.Site.Whitelist.ID | string | The ID for this entry. |
| SigSciences.Corp.Site.Whitelist.CreatedBy | string | The user who added this source. |
| SigSciences.Corp.Site.Whitelist.CreatedDate | date | The created date timestamp |
| SigSciences.Corp.Site.Whitelist.ExpiryDate | date | The expiration timestamp. |
Command Example
!sigsci-whitelist-add-ip ip=9.7.9.7 note=docdoc siteName=demisto
Context Example
{
"SigSciences.Corp.Site.Whitelist": {
"ExpiryDate": "",
"Note": "docdoc",
"Source": "9.7.9.7",
"CreatedBy": "user@demisto.com",
"CreatedDate": "2019-03-28T13:30:34Z",
"ID": "5c9ccc7a342a24019743d265"
}
}
Human Readable Output
Signal Sciences - Adding an IP to allow list
The IP 9.7.9.7 has been successfully added to allow list.
| Source | Note | Expiration date |
|---|---|---|
| 9.7.9.7 | docdoc | Not Set |
4. Add an IP address to a block list: sigsci-blacklist-add-ip
Adds an IP to a site’s block list, which resides on the Signal Sciences’ platform.
Base Command
sigsci-blacklist-add-ip
Input
| Argument Name | Description | Required |
|---|---|---|
| siteName | The site that holds the block list you wish to add to | Required |
| ip | The IP address to add to the site’s block list in CSV format. | Required |
| note | The note associated with the tag. | Required |
| expires | The datetime for the IP address to removed from the site’s block list (in RFC3339 format). To keep the IP address on the site’s block list indefinitely, do not specify this argument. | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| SigSciences.Corp.Site.Blacklist.Source | string | The IP address on the blacklist. |
| SigSciences.Corp.Site.Blacklist.Note | string | The note associated with the tag. |
| SigSciences.Corp.Site.Blacklist.ID | string | The ID for this entry. |
| SigSciences.Corp.Site.Blacklist.CreatedBy | string | The user who added this source. |
| SigSciences.Corp.Site.Blacklist.CreatedDate | date | The created date timestamp. |
| SigSciences.Corp.Site.Blacklist.ExpiryDate | date | The expiration timestamp. |
Command Example
!sigsci-blacklist-add-ip ip=5.7.5.7 note=docdoc siteName=demisto
Context Example
{
"SigSciences.Corp.Site.Blacklist": {
"ExpiryDate": "",
"Note": "docdoc",
"Source": "5.7.5.7",
"CreatedBy": "user@demisto.com",
"CreatedDate": "2019-03-28T13:30:35Z",
"ID": "5c9ccc7bf7c34301986b1d82"
}
}
Human Readable Output
Signal Sciences - Adding an IP to block list
The IP 5.7.5.7 has been successfully added to block list.
| Source | Note | Expiration date |
|---|---|---|
| 5.7.5.7 | docdoc | Not Set |
5. Remove an IP address from an allow list: sigsci-whitelist-remove-ip
Removes an IP address from a site’s allow list, which resides on the Signal Sciences’ platform.
Base Command
sigsci-whitelist-remove-ip
Input
| Argument Name | Description | Required |
|---|---|---|
| siteName | The site that contains the allow list you want to remove an IP address from. | Required |
| IP | The IP address entry to remove. | Required |
Context Output
There is no context output for this command.
Command Example
!sigsci-whitelist-remove-ip IP=4.7.4.7 siteName=demisto
6. Remove an IP address from a block list
Removes an IP from a site’s block list, which resides on the Signal Sciences’ platform.
Base Command
sigsci-blacklist-remove-ip
Input
| Argument Name | Description | Required |
|---|---|---|
| siteName | The site that contains the block list you want to remove an IP address from. | Required |
| IP | The IP address entry to remove. | Required |
Context Output
There is no context output for this command.
Command Example
!sigsci-blacklist-remove-ip IP=6.8.6.8 siteName=demisto
7. Get all site names
Returns all site names from the Signal Sciences platform.
Base Command
sigsci-get-sites
Input
There are no input arguments for this command.
Context Output
| Path | Type | Description |
|---|---|---|
| SigSciences.Site.Name | string | The site name. |
| SigSciences.Site.CreatedDate | date | The site creation date. |
8. Create a list for a site
Creates a new list for a given site on the Signal Sciences platform.
Base Command
sigsci-create-site-list
Input
| Argument Name | Description | Required |
|---|---|---|
| siteName | The name of the site in Signal Sciences you want to add a list to. | Required |
| list_name | The name of the list to create on Signal Sciences. | Required |
| list_type | The type for the list you wish to create on Signal Sciences. Legal types are IP, String, Country or Wildcard | Required |
| entries_list | A CSV list of values, consistent with the list’s type. | Required |
| description | Short text that describes the new list. | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| SigSciences.Corp.Site.List.Name | string | The name of the list. |
| SigSciences.Corp.Site.List.Type | string | The type of the list. |
| SigSciences.Corp.Site.List.Entries | unknown | The entry list of the list. |
| SigSciences.Corp.Site.List.ID | string | The ID of the list. |
| SigSciences.Corp.Site.List.Description | string | The description of the list. |
| SigSciences.Corp.Site.List.CreatedBy | string | The creator of the list. |
| SigSciences.Corp.Site.List.CreatedDate | string | The creation date of the list. |
| SigSciences.Corp.Site.List.UpdatedDate | string | The last update date of the list. |
Command Example
!sigsci-create-site-list entries_list=56.1.1.1 list_name=sitelistdoc list_type=IP siteName=demisto
9. Get information for a site list
Returns all the data about a site list.
Base Command
sigsci-get-site-list
Input
| Argument Name | Description | Required |
|---|---|---|
| siteName | The name of the site in Signal Sciences that the list you’re searching for belongs to. | Required |
| list_id | The ID of the list. | Required |
Context Output
| Path | Type | Description |
|---|---|---|
| SigSciences.Corp.Site.List.Name | string | The name of the list. |
| SigSciences.Corp.Site.List.Type | string | The type of the list. |
| SigSciences.Corp.Site.List.Entries | unknown | The entry list of the list. |
| SigSciences.Corp.Site.List.ID | unknown | The ID of the list. |
| SigSciences.Corp.Site.List.Description | unknown | The description of the list. |
| SigSciences.Corp.Site.List.CreatedBy | unknown | The creator of the list. |
| SigSciences.Corp.Site.List.CreatedDate | unknown | The creation date of the list. |
| SigSciences.Corp.Site.List.UpdatedDate | unknown | The last update date of the list. |
Command Example
!sigsci-get-site-list list_id=site.sitelistdoc3 siteName=demisto
Context Example
{
"SigSciences.Corp.Site.List": {
"Name": "sitelistdoc3",
"CreatedDate": "2019-03-28T09:20:34Z",
"UpdatedDate": "2019-03-28T09:53:01Z",
"CreatedBy": "user@demisto.com",
"Entries": [
"6.1.7.1",
"77.8.77.8"
],
"Type": "ip",
"ID": "site.sitelistdoc3",
"Description": ""
}
}
Human Readable Output
Found data about list with ID: site.sitelistdoc3
| Name | ID | Type | Entries | Created By | Created Date | Updated Date |
|---|---|---|---|---|---|---|
| sitelistdoc3 | site.sitelistdoc3 | ip | 6.1.7.1, 77.8.77.8 |
user@demisto.com | 2019-03-28T09:20:34Z | 2019-03-28T09:53:01Z |
10. Delete a site list
Deletes a site list in Signal Sciences.
Base Command
sigsci-delete-site-list
Input
| Argument Name | Description | Required |
|---|---|---|
| siteName | The name of the site in Signal Sciences you want to delete a list from. | Required |
| list_id | The ID of the list in Signal Sciences to delete. | Required |
Context Output
There is no context output for this command.
Command Example
!sigsci-delete-site-list list_id=site.sitelistdoc2 siteName=demisto
11. Update a site list
Updates a site list in Signal Sciences.
Base Command
sigsci-update-site-list
Input
| Argument Name | Description | Required |
|---|---|---|
| siteName | The name of the site in Signal Sciences that the list to update belongs to. | Required |
| list_id | The ID of the list to update. | Required |
| method | The method to use, must be “Add” or “Remove”. The method will determine whether the given entries are added to or removed from the list. | Required |
| entries_list | A CSV list of values, consistent with the list’s type. | Required |
| description | A description for the updated list. | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| SigSciences.Corp.Site.List.Name | string | The name of the list in Signal Sciences. |
| SigSciences.Corp.Site.List.Type | string | The type of the list in Signal Sciences. |
| SigSciences.Corp.Site.List.Entries | unknown | The entry list of the list in Signal Sciences. |
| SigSciences.Corp.Site.List.ID | string | The ID of the list in Signal Sciences. |
| SigSciences.Corp.Site.List.Description | string | The description of the list in Signal Sciences. Maximum is 140 characters. |
| SigSciences.Corp.Site.List.CreatedBy | string | The creator of the list in Signal Sciences. |
| SigSciences.Corp.Site.List.CreatedDate | string | The creation date of the list in Signal Sciences. |
| SigSciences.Corp.Site.List.UpdatedDate | string | The last update date of the list in Signal Sciences. |
Command Example
!sigsci-update-site-list entries_list=77.8.77.8 list_id=site.sitelistdoc3 method=Add siteName=demisto
Context Example
{
"SigSciences.Corp.Site.List": {
"Name": "sitelistdoc3",
"CreatedDate": "2019-03-28T09:20:34Z",
"UpdatedDate": "2019-03-28T09:53:01Z",
"CreatedBy": "user@demisto.com",
"Entries": [
"6.1.7.1",
"77.8.77.8"
],
"Type": "ip",
"ID": "site.sitelistdoc3",
"Description": ""
}
}
Human Readable Output
Signal Sciences - Updating a list
| Name | ID | Type | Entries | Created By | Created Date | Updated Date |
|---|---|---|---|---|---|---|
| sitelistdoc3 | site.sitelistdoc3 | ip | 6.1.7.1, 77.8.77.8 |
user@demisto.com | 2019-03-28T09:20:34Z | 2019-03-28T09:53:01Z |
12. Add an alert to a site
Adds a custom alert to a site in Signal Sciences.
Base Command
sigsci-add-alert
Input
| Argument Name | Description | Required |
|---|---|---|
| siteName | The name of the site to add an alert to. | Required |
| long_name | A human readable description of the alert. Must be between 3 and 25 characters. | Required |
| interval | The number of minutes of past traffic to examine. Must be 1, 10 or 60. | Required |
| tag_name | The name of the tag whose occurrences the alert is watching. Must match an existing tag. | Required |
| threshold | The number of occurrences of the tag in the specified interval that are required to trigger the alert. | Required |
| enabled | A flag to toggle this alert (“True” or “False”). | Required |
| action | A flag that describes what happens when the alert is triggered. “info” creates an incident in the dashboard. “flagged” creates an incident and blocks traffic for 24 hours. | Required |
Context Output
| Path | Type | Description |
|---|---|---|
| SigSciences.Corp.Site.Alert.ID | string | The unique ID of the alert. |
| SigSciences.Corp.Site.Alert.SiteID | string | The ID of the site. |
| SigSciences.Corp.Site.Alert.TagName | string | The name of the tag whose occurrences the alert is watching. |
| SigSciences.Corp.Site.Alert.LongName | string | A short description of the alert. |
| SigSciences.Corp.Site.Alert.Interval | number | The number of minutes of past traffic to examine. |
| SigSciences.Corp.Site.Alert.Threshold | number | The number of occurrences of the tag in the specified interval that are required to trigger the alert. |
| SigSciences.Corp.Site.Alert.BlockDurationSeconds | number | The number of seconds that this alert is active. |
| SigSciences.Corp.Site.Alert.SkipNotifications | boolean | A flag to disable external notifications - Slack, webhooks, emails, and so on. |
| SigSciences.Corp.Site.Alert.Enabled | boolean | A flag to toggle this alert. |
| SigSciences.Corp.Site.Alert.Action | string | A flag that describes what happens when the alert is triggered. |
| SigSciences.Corp.Site.Alert.CreatedDate | date | The timestamp of event (RFC3339 format). |
Command Example
!sigsci-add-alert action='info' enabled=False interval=60 long_name=tttt siteName=demisto tag_name=USERAGENT threshold=100
13. Get information for an alert
Retrieves data for an alert.
Base Command
sigsci-get-alert
Input
| Argument Name | Description | Required |
|---|---|---|
| siteName | The name of the site the alert you want to get data for belongs to. | Required |
| alert_id | The ID of the alert to retrieve. | Required |
Context Output
| Path | Type | Description |
|---|---|---|
| SigSciences.Corp.Site.Alert.ID | string | The unique ID of the alert. |
| SigSciences.Corp.Site.Alert.SiteID | string | The ID of the site. |
| SigSciences.Corp.Site.Alert.TagName | string | The name of the tag whose occurrences the alert is watching. |
| SigSciences.Corp.Site.Alert.LongName | string | A short description of the alert. |
| SigSciences.Corp.Site.Alert.Interval | number | The number of minutes of past traffic to examine. |
| SigSciences.Corp.Site.Alert.Threshold | number | The number of occurrences of the tag in the specified interval that are required to trigger the alert. |
| SigSciences.Corp.Site.Alert.BlockDurationSeconds | number | The number of seconds this alert is active. |
| SigSciences.Corp.Site.Alert.SkipNotifications | boolean | A flag to disable external notifications - Slack, webhooks, emails, and so on. |
| SigSciences.Corp.Site.Alert.Enabled | boolean | A flag to toggle this alert. |
| SigSciences.Corp.Site.Alert.Action | string | A flag that describes what happens when the alert is triggered. |
| SigSciences.Corp.Site.Alert.CreatedDate | date | The timestamp of the event (RFC3339 format). |
Command Example
!sigsci-get-alert alert_id=5b8ba7fd7a54b34f0c0f12cc siteName=demisto
Human Readable Output
14. Delete an alert from a site
Deletes an alert from a given site in Signal Sciences.
Base Command
sigsci-delete-alert
Input
| Argument Name | Description | Required |
|---|---|---|
| siteName | The name of the site to delete an alert from. | Required |
| alert_id | The ID of the alert to delete. | Required |
Context Output
There is no context output for this command.
Command Example
!sigsci-delete-alert alert_id=5b8ba7fd7a54b34f0c0f12cc siteName=demisto
15. Update attributes for an alert
Updates the attributes of a given alert.
Base Command
sigsci-update-alert
Input
| Argument Name | Description | Required |
|---|---|---|
| siteName | The site of the alert to update. | Required |
| alert_id | The ID of the alert to update. | Required |
| tag_name | The name of the tag whose occurrences the alert is watching. | Required |
| long_name | A human readable description of the alert. Must be between 3 and 25 characters. | Required |
| interval | The number of minutes of past traffic to examine. | Required |
| threshold | The number of occurrences of the tag in the specified interval that are required to trigger the alert. | Required |
| enabled | A flag to toggle this alert. | Required |
| action | A flag that describes what happens when the alert is triggered. “info” creates an incident in the dashboard. “flagged” creates an incident and blocks traffic for 24 hours. | Required |
Context Output
| Path | Type | Description |
|---|---|---|
| SigSciences.Corp.Site.Alert.CreatedDate | string | The unique ID of the alert. |
| SigSciences.Corp.Site.Alert.SiteID | string | The ID of the site. |
| SigSciences.Corp.Site.Alert.TagName | string | The name of the tag whose occurrences the alert is watching. |
| SigSciences.Corp.Site.Alert.LongName | string | A short description of the alert. |
| SigSciences.Corp.Site.Alert.Interval | number | The number of minutes of past traffic to examine. |
| SigSciences.Corp.Site.Alert.Threshold | number | The number of occurrences of the tag in the specified interval that are required to trigger the alert. |
| SigSciences.Corp.Site.Alert.BlockDurationSeconds | number | The number of seconds that this alert is active. |
| SigSciences.Corp.Site.Alert.SkipNotifications | boolean | A flag to disable external notifications - Slack, webhooks, emails, and so on. |
| SigSciences.Corp.Site.Alert.Enabled | boolean | A flag to toggle this alert. |
| SigSciences.Corp.Site.Alert.Action | string | A flag that describes what happens when the alert is triggered. |
| SigSciences.Corp.Site.Alert.CreatedDate | date | The timestamp of event (RFC3339 format). |
Command Example
!sigsci-update-alert action=flagged alert_id=5c9c8f35c7213901971d2e5a enabled=False interval=10 long_name=ggggg siteName=demisto tag_name=SQLI threshold=40
Context Example
{
"SigSciences.Corp.Site.Alert": {
"LongName": "ggggg",
"SkipNotifications": "",
"Interval": 10,
"Enabled": true,
"Threshold": 40,
"SiteID": "",
"TagName": "SQLI",
"CreatedDate": "2019-03-28T09:09:09Z",
"Action": "flagged",
"ID": "5c9c8f35c7213901971d2e5a",
"BlockDurationSeconds": ""
}
}
Human Readable Output
Updated alert 5c9c8f35c7213901971d2e5a. new values:
| ID | Created Date | Tag Name | Action | Long Name | Interval (In Minutes) | Threshold | Enabled |
|---|---|---|---|---|---|---|---|
| 5c9c8f35c7213901971d2e5a | 2019-03-28T09:09:09Z | SQLI | flagged | ggggg | 10 | 40 | true |
16. Get all alerts for a site
Retrieves all alerts for given a site.
Base Command
sigsci-get-all-alerts
Input
| Argument Name | Description | Required |
|---|---|---|
| siteName | The name of site to get alerts for. | Required |
Context Output
| Path | Type | Description |
|---|---|---|
| SigSciences.Corp.Site.Alert.ID | string | The unique ID of the alert. |
| SigSciences.Corp.Site.Alert.SiteID | string | The ID of the site. |
| SigSciences.Corp.Site.Alert.TagName | string | The name of the tag whose occurrences the alert is watching. |
| SigSciences.Corp.Site.Alert.LongName | string | A short description of the alert. |
| SigSciences.Corp.Site.Alert.Interval | number | The number of minutes of past traffic to examine. |
| SigSciences.Corp.Site.Alert.Threshold | number | The number of occurrences of the tag in the specified interval that are required to trigger the alert. |
| SigSciences.Corp.Site.Alert.BlockDurationSeconds | number | The number of seconds this alert is active. |
| SigSciences.Corp.Site.Alert.SkipNotification | boolean | A flag to disable external notifications - Slack, webhooks, emails, and so on. |
| SigSciences.Corp.Site.Alert.Enabled | boolean | A flag to toggle this alert. |
| SigSciences.Corp.Site.Alert.Action | string | A flag that describes what happens when the alert is triggered. |
| SigSciences.Corp.Site.Alert.CreatedDate | date | The timestamp of event (RFC3339 format). |
Command Example
!sigsci-get-all-alerts siteName=demisto
Context Example
{
"SigSciences.Corp.Site.Alert": [
{
"LongName": "ggggg",
"SkipNotifications": "",
"Interval": 10,
"Enabled": true,
"Threshold": 40,
"SiteID": "",
"TagName": "SQLI",
"CreatedDate": "2019-03-28T09:09:09Z",
"Action": "flagged",
"ID": "5c9c8f35c7213901971d2e5a",
"BlockDurationSeconds": ""
},
{
"LongName": "The site's Online Agent count is zero",
"SkipNotifications": "",
"Interval": 5,
"Enabled": false,
"Threshold": 0,
"SiteID": "",
"TagName": "agent_count",
"CreatedDate": "2018-08-30T21:00:03Z",
"Action": "siteMetricInfo",
"ID": "5b885ad33be3360a3f80237c",
"BlockDurationSeconds": 21600
},
{
"LongName": "The average RPS across all agents is less than 10",
"SkipNotifications": "",
"Interval": 5,
"Enabled": false,
"Threshold": 3000,
"SiteID": "",
"TagName": "requests_total",
"CreatedDate": "2018-08-30T21:00:03Z",
"Action": "siteMetricInfo",
"ID": "5b885ad33be3360a3f80237b",
"BlockDurationSeconds": 21600
}
]
}
Human Readable Output
Signal Sciences - Alert list
Number of alerts in site: 3
| ID | Created Date | Tag Name | Action | Long Name | Interval (In Minutes) | Threshold | Block Duration Seconds | Enabled |
|---|---|---|---|---|---|---|---|---|
| 5c9c8f35c7213901971d2e5a | 2019-03-28T09:09:09Z | SQLI | flagged | ggggg | 10 | 40 | true | |
| 5b885ad33be3360a3f80237c | 2018-08-30T21:00:03Z | agent_count | siteMetricInfo | The site’s Online Agent count is zero | 5 | 0 | 21600 | false |
| 5b885ad33be3360a3f80237b | 2018-08-30T21:00:03Z | requests_total | siteMetricInfo | The average RPS across all agents is less than 10 | 5 | 3000 | 21600 | false |
17. Get all lists for a site
Retrieves all site lists for a given site.
Base Command
sigsci-get-all-site-lists
Input
| Argument Name | Description | Required |
|---|---|---|
| siteName | The name of the site to retrieve lists for. | Required |
Context Output
| Path | Type | Description |
|---|---|---|
| SigSciences.Corp.Site.List.Name | string | The name of the list in Signal Sciences. |
| SigSciences.Corp.Site.List.Type | string | The type of the list in Signal Sciences. |
| SigSciences.Corp.Site.List.Entries | unknown | The entry list of the list in Signal Sciences. |
| SigSciences.Corp.Site.List.ID | string | The ID of the list in Signal Sciences. |
| SigSciences.Corp.Site.List.Description | string | The description of the list in Signal Sciences. Maximum is 140 characters. |
| SigSciences.Corp.Site.List.CreatedBy | string | The creator of the list in Signal Sciences. |
| SigSciences.Corp.Site.List.CreatedDate | string | The creation date of the list in Signal Sciences. |
| SigSciences.Corp.Site.List.UpdatedDate | string | The last update date of the list in Signal Sciences. |
Command Example
!sigsci-get-all-site-lists siteName=demisto
Context Example
{
"SigSciences.Corp.Site.List": [
{
"Name": "sitelistdoc",
"CreatedDate": "2019-03-28T09:52:55Z",
"UpdatedDate": "2019-03-28T09:52:55Z",
"CreatedBy": "user@demisto.com",
"Entries": [
"56.1.1.1"
],
"Type": "ip",
"ID": "site.sitelistdoc",
"Description": ""
},
{
"Name": "sitelistdoc3",
"CreatedDate": "2019-03-28T09:20:34Z",
"UpdatedDate": "2019-03-28T13:30:41Z",
"CreatedBy": "user@demisto.com",
"Entries": [
"6.1.7.1",
"77.8.77.8"
],
"Type": "ip",
"ID": "site.sitelistdoc3",
"Description": ""
}
]
}
Human Readable Output
Signal Sciences - list of site lists
Number of site lists in site: 2
| Name | ID | Type | Entries | Created By | Created Date | Updated Date |
|---|---|---|---|---|---|---|
| sitelistdoc | site.sitelistdoc | ip | 56.1.1.1 | user@demisto.com | 2019-03-28T09:52:55Z | 2019-03-28T09:52:55Z |
| sitelistdoc3 | site.sitelistdoc3 | ip | 6.1.7.1, 77.8.77.8 |
user@demisto.com | 2019-03-28T09:20:34Z | 2019-03-28T13:30:41Z |
18. Create a corp list
Creates a new corp list.
Base Command
sigsci-create-corp-list
Input
| Argument Name | Description | Required |
|---|---|---|
| list_name | A name for the new list. | Required |
| list_type | The type for the new list (“IP”, “String”, “Country”, or “Wildcard”). | Required |
| entries_list | A CSV list of values, consistent with the list’s type. | Required |
| description | Short text that describes the new list. | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| SigSciences.Corp.List.Name | string | The name of the list. |
| SigSciences.Corp.List.Type | string | The type of the list. |
| SigSciences.Corp.List.Entries | unknown | The entry list of the list. |
| SigSciences.Corp.List.ID | string | The ID of the list. |
| SigSciences.Corp.List.Description | string | The description of the list. |
| SigSciences.Corp.List.CreatedBy | string | The creator of the list. |
| SigSciences.Corp.List.CreatedDate | string | The creation date of the list. |
| SigSciences.Corp.List.UpdatedDate | string | The last update date of the list. |
Command Example
!sigsci-create-corp-list entries_list=3.5.3.5 list_name=fordoc list_type=IP
19. Get information for a corp list
Retrieves all data about a given corp list.
Base Command
sigsci-get-corp-list
Input
| Argument Name | Description | Required |
|---|---|---|
| list_id | The ID of the list to get data for. | Required |
Context Output
| Path | Type | Description |
|---|---|---|
| SigSciences.Corp.List.Name | unknown | The name of the list. |
| SigSciences.Corp.List.Type | unknown | The type of the list. |
| SigSciences.Corp.List.Entries | unknown | The entry list of the list. |
| SigSciences.Corp.List.ID | unknown | The ID of the list. |
| SigSciences.Corp.List.Description | unknown | The description of the list. |
| SigSciences.Corp.List.CreatedBy | unknown | The creator of the list. |
| SigSciences.Corp.List.CreatedDate | unknown | The creation date of the list. |
| SigSciences.Corp.List.UpdatedDate | unknown | The last update date of the list. |
Command Example
!sigsci-get-corp-list list_id=corp.fordoc2
Context Example
{
"SigSciences.Corp.List": {
"Name": "fordoc2",
"CreatedDate": "2019-03-28T09:14:43Z",
"UpdatedDate": "2019-03-28T09:53:14Z",
"CreatedBy": "user@demisto.com",
"Entries": [
"44.2.44.2",
"55.7.55.7"
],
"Type": "ip",
"ID": "corp.fordoc2",
"Description": ""
}
}
Human Readable Output
Found data about list with ID: corp.fordoc2
| Name | ID | Type | Entries | Created By | Created Date | Updated Date |
|---|---|---|---|---|---|---|
| fordoc2 | corp.fordoc2 | ip | 44.2.44.2, 55.7.55.7 |
user@demisto.com | 2019-03-28T09:14:43Z | 2019-03-28T09:53:14Z |
20. Delete a corp list
Deletes a given corp list.
Base Command
sigsci-delete-corp-list
Input
| Argument Name | Description | Required |
|---|---|---|
| list_id | The ID of the list to delete. | Required |
Context Output
There is no context output for this command.
Command Example
!sigsci-delete-corp-list list_id=corp.maya
Human Readable Output
21. Update a corp list
Updates (add or delete) entries for a given corp list.
Base Command
sigsci-update-corp-list
Input
| Argument Name | Description | Required |
|---|---|---|
| list_id | The ID of the list you wish to update | Required |
| method | The method to use - must be “Add” or “Remove”. The method will determine whether the entries you provide are added to the list or removed from it | Required |
| entries_list | A list of values, consistent with the list’s type, separated by commas | Required |
| description | A description for the updated list. | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| SigSciences.Corp.List.Name | unknown | The name of the list. |
| SigSciences.Corp.List.Type | unknown | The type of the list. |
| SigSciences.Corp.List.Entries | unknown | The entry list of the list. |
| SigSciences.Corp.List.ID | unknown | The ID of the list. |
| SigSciences.Corp.List.Description | unknown | The description of the list. |
| SigSciences.Corp.List.CreatedBy | unknown | The creator of the list. |
| SigSciences.Corp.List.CreatedDate | unknown | The creation date of the list. |
| SigSciences.Corp.List.UpdatedDate | unknown | The last update date of the list. |
Command Example
!sigsci-update-corp-list entries_list=55.7.55.7 list_id=corp.fordoc2 method=Add
Context Example
{
"SigSciences.Corp.List": {
"Name": "fordoc2",
"CreatedDate": "2019-03-28T09:14:43Z",
"UpdatedDate": "2019-03-28T09:53:14Z",
"CreatedBy": "user@demisto.com",
"Entries": [
"44.2.44.2",
"55.7.55.7"
],
"Type": "ip",
"ID": "corp.fordoc2",
"Description": ""
}
}
Human Readable Output
Signal Sciences - Updating a list
| Name | ID | Type | Entries | Created By | Created Date | Updated Date |
|---|---|---|---|---|---|---|
| fordoc2 | corp.fordoc2 | ip | 44.2.44.2, 55.7.55.7 |
user@demisto.com | 2019-03-28T09:14:43Z | 2019-03-28T09:53:14Z |
22. Get information for all lists of a corp
Retrieves data about all lists for the given corp.
Base Command
sigsci-get-all-corp-lists
Input
There are no input arguments for this command.
Context Output
| Path | Type | Description |
|---|---|---|
| SigSciences.Corp.List.Name | unknown | The name of the list. |
| SigSciences.Corp.List.Type | unknown | The type of the list. |
| SigSciences.Corp.List.Entries | unknown | The entry list of the list. |
| SigSciences.Corp.List.ID | unknown | The ID of the list. |
| SigSciences.Corp.List.Description | unknown | The description of the list. |
| SigSciences.Corp.List.CreatedBy | unknown | The creator of the list. |
| SigSciences.Corp.List.CreatedDate | unknown | The creation date of the list. |
| SigSciences.Corp.List.UpdatedDate | unknown | The last update date of the list. |
23. Get a list of events
Fetches events from Signal Sciences.
Base Command
sigsci-fetch-events
Input
| Argument Name | Description | Required |
|---|---|---|
| siteName | The name of the site to fetch events from. | Required |
| from_time | The POSIX Unix time to start. | Optional |
| until_time | The POSIX Unix time to end. | Optional |
| sort | The sort order (“asc” or “desc”). | Optional |
| since_id | The ID of the first object in the set. | Optional |
| max_id | The ID of the last object in the set. | Optional |
| limit | The maximum number of entries to return. | Optional |
| page | The page of the results. | Optional |
| action | The action to filter by (‘flagged’ or ‘info’). | Optional |
| tag | The tag to filter by. Must be a valid tag name. | Optional |
| ip | The ID to filter by. | Optional |
| status | The status to filter by (“active” or “expired”). | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| SigSciences.Corp.Site.Event.ID | string | The unique ID of the event. |
| SigSciences.Corp.Site.Event.Timestamp | date | The timestamp of the event (RFC3339 format). |
| SigSciences.Corp.Site.Event.Source | string | The source information, for example, “IP”. |
| SigSciences.Corp.Site.Event.RemoteCountryCode | string | The country code. |
| SigSciences.Corp.Site.Event.RemoteHostname | string | The remote hostname. |
| SigSciences.Corp.Site.Event.UserAgents | unknown | An array of user agents. |
| SigSciences.Corp.Site.Event.Action | unknown | If “flagged”, the IP address is flagged and subsequent malicious requests will be blocked. If “info”, the IP address is flagged and subsequent requests will be logged. |
| SigSciences.Corp.Site.Event.Reasons | unknown | The reason the event was triggered. |
| SigSciences.Corp.Site.Event.RequestCount | number | The total number of requests. |
| SigSciences.Corp.Site.Event.TagCount | number | The total number of tags. |
| SigSciences.Corp.Site.Event.Window | number | The time window (in seconds) when the items were detected. |
| SigSciences.Corp.Site.Event.DateExpires | string | The date the event expires (RFC3339 format). |
| SigSciences.Corp.Site.Event.ExpiredBy | string | The email address of the user that expired the event (if the event is expired manually). |
24. Get an event by event ID
Retrieves an event by the event ID.
Base Command
sigsci-get-event-by-id
Input
| Argument Name | Description | Required |
|---|---|---|
| siteName | Name of the site to get the event from | Required |
| event_id | The ID of the event. | Required |
Context Output
| Path | Type | Description |
|---|---|---|
| SigSciences.Corp.Site.Event.ID | unknown | The unique ID of the event. |
| SigSciences.Corp.Site.Event.Timestamp | unknown | The timestamp of the event (RFC3339 format). |
| SigSciences.Corp.Site.Event.Source | unknown | Source information, for example, “IP”. |
| SigSciences.Corp.Site.Event.RemoteCountryCode | unknown | The country code. |
| SigSciences.Corp.Site.Event.RemoteHostname | unknown | The remote hostname. |
| SigSciences.Corp.Site.Event.UserAgents | unknown | An array of user agents. |
| SigSciences.Corp.Site.Event.Action | unknown | If “flagged”, the IP address is flagged and subsequent malicious requests will be blocked. If “info”, the IP address is flagged and subsequent requests will be logged. |
| SigSciences.Corp.Site.Event.Reasons | unknown | The reason the event was triggered. |
| SigSciences.Corp.Site.Event.RequestCount | unknown | The total number of requests. |
| SigSciences.Corp.Site.Event.TagCount | unknown | The total number of tags. |
| SigSciences.Corp.Site.Event.Window | unknown | The time window (in seconds) when the items were detected. |
| SigSciences.Corp.Site.Event.DateExpires | unknown | The date the event expires (RFC3339 format). |
| SigSciences.Corp.Site.Event.ExpiredBy | unknown | The email address of the user that expired the event (if the event is expired manually). |
25. Expire an event
Expires a given event.
Base Command
sigsci-expire-event
Input
| Argument Name | Description | Required |
|---|---|---|
| siteName | The name of the site to expire an event from. | Required |
| event_id | The ID of the event to expire. | Required |
26. Get requests for a site
Retrieves requests from a given site according to a search query.
Base Command
sigsci-get-requests
Input
| Argument Name | Description | Required |
|---|---|---|
| siteName | The name of the site to get requests from. | Required |
| page | The page of the results. Maximum is 1000 requests. | Optional |
| limit | The number of entries to return. | Optional |
| q | The search query, in Signal Sciences syntax. If a query is not supplied, no requests will be returned. | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| SigSciences.Corp.Site.Request.ID | unknown | The unique ID of the request. |
| SigSciences.Corp.Site.Request.ServerHostName | unknown | The server hostname. |
| SigSciences.Corp.Site.Request.RemoteIP | unknown | The remote IP address. |
| SigSciences.Corp.Site.Request.RemoteHostName | unknown | The remote hostname. |
| SigSciences.Corp.Site.Request.RemoteCountryCode | unknown | The remote country code. |
| SigSciences.Corp.Site.Request.UserAgent | unknown | The user agent of the request. |
| SigSciences.Corp.Site.Request.Timestamp | unknown | The timestamp (RFC3339 format). |
| SigSciences.Corp.Site.Request.Method | unknown | The HTTP method, for example, “PUT”. |
| SigSciences.Corp.Site.Request.ServerName | unknown | The server name. |
| SigSciences.Corp.Site.Request.Protocol | unknown | The HTTP protocol, for example, “HTTP/1.1” . |
| SigSciences.Corp.Site.Request.Path | unknown | The path. |
| SigSciences.Corp.Site.Request.URI | unknown | The URI. |
| SigSciences.Corp.Site.Request.ResponseCode | unknown | The HTTP response code. |
| SigSciences.Corp.Site.Request.ResponseSize | unknown | The HTTP response size. |
| SigSciences.Corp.Site.Request.ResponseMillis | unknown | The response time in millis. |
| SigSciences.Corp.Site.Request.AgentResponseCode | unknown | The agent response code. |
| SigSciences.Corp.Site.Request.Tags | unknown | The array of relevant tags. |
27. Get a request by request ID
Retrieves a request by request ID.
Base Command
sigsci-get-request-by-id
Input
| Argument Name | Description | Required |
|---|---|---|
| siteName | The name of the site to get from. | Required |
| request_id | The ID of the request to get. | Required |
Context Output
| Path | Type | Description |
|---|---|---|
| SigSciences.Corp.Site.Request.ID | unknown | The unique ID of the request. |
| SigSciences.Corp.Site.Request.ServerHostName | unknown | Server hostname. |
| SigSciences.Corp.Site.Request.RemoteIP | unknown | The remote IP address. |
| SigSciences.Corp.Site.Request.RemoteHostName | unknown | The remote hostname. |
| SigSciences.Corp.Site.Request.RemoteCountryCode | unknown | The remote country code. |
| SigSciences.Corp.Site.Request.UserAgent | unknown | The user agent of the request. |
| SigSciences.Corp.Site.Request.Timestamp | unknown | The timestamp RFC3339 date time serverHostname string. |
| SigSciences.Corp.Site.Request.Method | unknown | The HTTP method, for example, “PUT”. |
| SigSciences.Corp.Site.Request.ServerName | unknown | The server name. |
| SigSciences.Corp.Site.Request.Protocol | unknown | The HTTP protocol, for example “HTTP/1.1”. |
| SigSciences.Corp.Site.Request.Path | unknown | The path. |
| SigSciences.Corp.Site.Request.URI | unknown | The URI. |
| SigSciences.Corp.Site.Request.ResponseCode | unknown | The HTTP response code. |
| SigSciences.Corp.Site.Request.ResponseSize | unknown | The HTTP response size. |
| SigSciences.Corp.Site.Request.ResponseMillis | unknown | The response time in milliseconds. |
| SigSciences.Corp.Site.Request.AgentResponseCode | unknown | The agent response code. |
| SigSciences.Corp.Site.Request.Tags | unknown | An array of relevant tags. |
sigsci-get-events
Fetches events from Signal Sciences.
Base Command
sigsci-get-events
Input
| Argument Name | Description | Required |
|---|---|---|
| siteName | The name of the site to fetch events from. | Required |
| from_time | The POSIX Unix time to start. | Optional |
| until_time | The POSIX Unix time to end. . | Optional |
| sort | The sort order (“asc” or “desc”). Possible values are: asc, desc. | Optional |
| since_id | The ID of the first object in the set. | Optional |
| max_id | The ID of the last object in the set. . | Optional |
| limit | The maximum number of entries to return. | Optional |
| page | The page of the results. | Optional |
| action | The action to filter by (‘flagged’ or ‘info’). . Possible values are: flagged, info. | Optional |
| tag | The tag to filter by. Must be a valid tag name. | Optional |
| ip | The ID to filter by. | Optional |
| status | The status to filter by (“active” or “expired”). Possible values are: active, expired. | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| SigSciences.Corp.Site.Event.ID | string | The unique ID of the event. |
| SigSciences.Corp.Site.Event.Timestamp | date | The timestamp of the event (RFC3339 format). |
| SigSciences.Corp.Site.Event.Source | string | The source information, for example, “IP”. |
| SigSciences.Corp.Site.Event.RemoteCountryCode | string | The country code. |
| SigSciences.Corp.Site.Event.RemoteHostname | string | The remote hostname. |
| SigSciences.Corp.Site.Event.UserAgents | unknown | An array of user agents. |
| SigSciences.Corp.Site.Event.Action | unknown | If “flagged”, the IP address is flagged and subsequent malicious requests will be blocked. If “info”, the IP address is flagged and subsequent requests will be logged. |
| SigSciences.Corp.Site.Event.Reasons | unknown | The reason the event was triggered. |
| SigSciences.Corp.Site.Event.RequestCount | number | The total number of requests. |
| SigSciences.Corp.Site.Event.TagCount | number | The total number of tags. |
| SigSciences.Corp.Site.Event.Window | number | The time window (in seconds) when the items were detected. |
| SigSciences.Corp.Site.Event.DateExpires | string | The date the event expires (RFC3339 format). |
| SigSciences.Corp.Site.Event.ExpiredBy | string | The email address of the user that expired the event (if the event is expired manually). |
Configuration parameters
Email— Email (required)Token— Tokencred_token—corpName— Corporation Name (should match the pattern [0-9a-z_.-]+) (required)isFetch— Fetch incidentsincidentType— Incident typeincidentFetchInterval— Incidents Fetch Intervalfetch_interval— Fetch Interval (in minutes)sites_to_fetch— CSV list of sites to fetch from. If no sites are specified, events from all corporation's sites will be fetched.insecure— Trust any certificate (not secure)proxy— Use system proxy settings
Commands (27)
-
sigsci-add-alertAdds a custom alert to a site in Signal Sciences.
-
sigsci-blacklist-add-ipAdds an IP to a site's block list, which resides on the Signal Sciences' platform.
-
sigsci-blacklist-remove-ipRemoves an IP from a site's block list, which resides on the Signal Sciences' platform.
-
sigsci-create-corp-listCreates a new corp list.
-
sigsci-create-site-listCreates a new list for a given site on the Signal Sciences platform.
-
sigsci-delete-alertDeletes an alert from a given site in Signal Sciences.
-
sigsci-delete-corp-listDeletes a given corp list.
-
sigsci-delete-site-listDeletes a site list in Signal Sciences.
-
sigsci-expire-eventExpires a given event.
-
sigsci-get-alertRetrieves data for an alert.
-
sigsci-get-all-alertsRetrieves all alerts for given a site.
-
sigsci-get-all-corp-listsRetrieves data about all lists for the given corp.
-
sigsci-get-all-site-listsRetrieves all site lists for a given site.
-
sigsci-get-blacklistFetches a site's block list, which resides on the Signal Sciences' platform.
-
sigsci-get-corp-listRetrieves all data about a given corp list.
-
sigsci-get-event-by-idRetrieves an event by the event ID.
-
sigsci-get-eventsFetches events from Signal Sciences.
-
sigsci-get-request-by-idRetrieves a request by request ID.
-
sigsci-get-requestsRetrieves requests from a given site according to a search query.
-
sigsci-get-site-listReturns all the data about a site list.
-
sigsci-get-sitesReturns all site names from the Signal Sciences platform.
-
sigsci-get-whitelistFetches a site's allow list, which resides on the Signal Sciences' platform.
-
sigsci-update-alertUpdates the attributes of a given alert.
-
sigsci-update-corp-listUpdates (add or delete) entries for a given corp list.
-
sigsci-update-site-listUpdates a site list in Signal Sciences.
-
sigsci-whitelist-add-ipAdds an IP address to a site's allow list, which resides on the Signal Sciences' platform.
-
sigsci-whitelist-remove-ipRemoves an IP address from a site's allow list, which resides on the Signal Sciences' platform.
import demistomock as demisto from CommonServerPython import * from CommonServerUserPython import * """ IMPORTS """ import json import requests """ GLOBAL VARS """ """ GLOBAL VARS """ USE_SSL = not demisto.params().get("insecure", False) handle_proxy() EMAIL = demisto.params()["Email"] TOKEN = secret_key = demisto.params().get("cred_token", {}).get("password") or demisto.params()["Token"] CORPNAME = demisto.params()["corpName"] FETCH_INTERVAL = demisto.params()["fetch_interval"] SITES_TO_FETCH = demisto.params().get("sites_to_fetch", None) SERVER_URL = "https://dashboard.signalsciences.net/api/v0/" """SUFFIX ENDPOINTS""" GET_SITES_SUFFIX = "corps/{0}/sites" WHITELIST_SUFFIX = "corps/{0}/sites/{1}/whitelist" BLACKLIST_SUFFIX = "corps/{0}/sites/{1}/blacklist" DELETE_WHITELIST_IP_SUFFIX = "corps/{0}/sites/{1}/whitelist/{2}" DELETE_BLACKLIST_IP_SUFFIX = "corps/{0}/sites/{1}/blacklist/{2}" SITE_CREATE_LIST_SUFFIX = "corps/{0}/sites/{1}/lists" SITE_ACCESS_LIST_SUFFIX = "corps/{0}/sites/{1}/lists/{2}" SITE_CREATE_ALERT_SUFFIX = "corps/{0}/sites/{1}/alerts" SITE_ACCESS_ALERT_SUFFIX = "corps/{0}/sites/{1}/alerts/{2}" CREATE_CORP_LIST_SUFFIX = "corps/{0}/lists" ACCESS_CORP_LIST_SUFFIX = "corps/{0}/lists/{1}" GET_EVENTS_SUFFIX = "/corps/{0}/sites/{1}/events" ACCESS_EVENT_SUFFIX = "/corps/{0}/sites/{1}/events/{2}" EXPIRE_EVENT_SUFFIX = "/corps/{0}/sites/{1}/events/{2}/expire" GET_REQUESTS_SUFFIX = "/corps/{0}/sites/{1}/requests" ACCESS_REQUEST_SUFFIX = "/corps/{0}/sites/{1}/requests/{2}" """TABLE TITLES""" WHITELIST_TITLE = "Signal Sciences - Whitelist" BLACKLIST_TITLE = "Signal Sciences - Blacklist" SITES_LIST_TITLE = "Sites list" ADD_IP_TO_WHITELIST_TITLE = "Signal Sciences - Adding an IP to Whitelist" ADD_IP_TO_BLACKLIST_TITLE = "Signal Sciences - Adding an IP to Blacklist" ADD_ALERT_TITLE = "Signal Sciences - Adding a new custom alert" UPDATE_LIST_TITLE = "Signal Sciences - Updating a list" ALERT_LIST_TITLE = "Signal Sciences - Alert list" LIST_OF_SITE_LISTS_TITLE = "Signal Sciences - list of site lists" LIST_OF_CORP_LISTS_TITLE = "Signal Sciences - list of corp lists" LIST_OF_EVENTS_TITLE = "Signal Sciences - list of events" LIST_OF_REQUESTS_TITLE = "Signal Sciences - list of requests" CREATE_SITE_LIST_TITLE = "Signal Sciences - creating a new site list \n\n List {0} has been successfully created" CREATE_CORP_LIST_TITLE = "Signal Sciences - creating a new corp list \n\n List {0} has been successfully created" DELETE_CORP_LIST_TITLE = "### Signal Sciences - deleting corp list \n\n List {0} has been successfully removed" EXPIRE_EVENT_TITLE = "### Signal Sciences - expiring event \n\n Event {0} has been successfully expired" WHITELIST_REMOVE_IP_TITLE = ( "### Signal Sciences - Removing an IP from Whitelist \n\n The IP {0} has been successfully removed from Whitelist." ) DELETE_SITE_LIST_TITLE = "### Signal Sciences - deleting site list \n\n The list has been succesfully removed" BLACKLIST_REMOVE_IP_TITLE = ( "### Signal Sciences - Removing an IP from Blacklist \n\n The IP {0} has been successfully removed from Blacklist." ) IP_ADDED_TO_WHITELIST_TITLE = "The IP {0} has been successfully added to whitelist." IP_ADDED_TO_BLACKLIST_TITLE = "The IP {0} has been successfully added to blacklist." """TABLE HEADERS""" ADD_IP_HEADERS = ["Source", "Note", "Expiration date"] WHITELIST_OR_BLACKLIST_HEADERS = ["ID", "Source", "Expiry Date", "Note", "Created Date", "Created By"] LIST_HEADERS = ["Name", "ID", "Type", "Entries", "Description", "Created By", "Created Date", "Updated Date"] GET_SITE_HEADERS = ["Name", "Created Date"] EVENT_HEADERS = [ "ID", "Timestamp", "Source", "Remote Country Code", "Action", "Reasons", "Remote Hostname", "User Agents", "Request Count", "Tag Count", "Window", "Date Expires", "Expired By", ] REQUEST_HEADER = [ "ID", "Timestamp", "Remote Country Code", "Remote Hostname", "Remote IP", "User Agent", "Method", "Server Name", "Protocol", "Path", "URI", "Response Code", "Response Size", "Response Millis", "Agent Response Code", "Tags", ] ALERT_HEADERS = [ "ID", "Site ID", "Created Date", "Tag Name", "Action", "Long Name", "Interval (In Minutes)", "Threshold", "Block Duration Seconds", "Skip Notifications", "Enabled", ] """List Types dict""" LEGAL_SIGSCI_LIST_TYPES = {"ip", "country", "string", "wildcard"} """ HELPER FUNCTIONS """ def camel_case_to_spaces(string_in_camel_case): """Given a string in camelcase, will turn it into spaces Args: string_in_camel_case(String): the string in camel case Returns: A new string, separated by spaces and every word starts with a capital letter """ string_with_underscores = camel_case_to_underscore(string_in_camel_case) new_string_with_spaces = string_with_underscores.replace("_", " ") return new_string_with_spaces.title() def dict_keys_from_camelcase_to_spaces(dict_with_camelcase_keys): """Given a dict with keys in camelcase, returns a copy of it with keys in spaces (helloWorld becomes Hello World) Args: dict_with_camelcase_keys(Dictionary): the original dictionary, with keys in camelcase Returns: A new dictionary, with keys separated by spaces """ dict_with_spaces_in_keys = {} for key in dict_with_camelcase_keys: key_with_spaces = camel_case_to_spaces(key) dict_with_spaces_in_keys[key_with_spaces] = dict_with_camelcase_keys[key] return dict_with_spaces_in_keys def return_list_of_dicts_with_spaces(list_of_camelcase_dicts): """Given a list of dicts, iterates over it and for each dict makes all the keys with spaces instead of camelcase Args: list_of_camelcase_dicts(List): array of dictionaries Returns: A new array of dictionaries, with keys including spaces instead of camelcase """ dicts_with_spaces = [] for dict_camelcase in list_of_camelcase_dicts: dict_with_spaces = dict_keys_from_camelcase_to_spaces(dict_camelcase) dicts_with_spaces.append(dict_with_spaces) return dicts_with_spaces def has_api_call_failed(res): """ Note: In SigSci, if an API call fails it returns a json with only 'message' in it. """ return "message" in res def is_error_status(status): return int(status) >= 400 def return_error_message(results_json): error_message = results_json.get("message", None) if error_message is None: return_error("Error: An error occured") return_error(f"Error: {error_message}") def http_request(method, url, params_dict=None, data=None, use_format_instead_of_raw=False): LOG(f"running {method} request with url={url}\nparams={json.dumps(params_dict)}") if not TOKEN: raise DemistoException("Token must be provided.") headers = {"Content-Type": "application/json", "x-api-user": EMAIL, "x-api-token": TOKEN} try: # Some commands in Signal Sciences require sending the data in raw, and some in format # To send in format, we use the 'data' argument in requests. for raw, we use the 'json' argument. if use_format_instead_of_raw: res = requests.request(method, url, verify=USE_SSL, params=params_dict, headers=headers, data=json.dumps(data)) else: res = requests.request(method, url, verify=USE_SSL, params=params_dict, headers=headers, json=data) if is_error_status(res.status_code): return_error_message(res.json()) # references to delete from whitelist/blacklist only if "whitelist/" in url or "blacklist/" in url: return {} if res.status_code == 204: return {} res_json = res.json() if has_api_call_failed(res_json): return {} return res_json except Exception as e: LOG(e) raise (e) def is_legal_list_type(list_type): return list_type.lower() in LEGAL_SIGSCI_LIST_TYPES def represents_int(string_var): if "." in string_var: return False if string_var[0] in ("-", "+"): return string_var[1:].isdigit() return string_var.isdigit() def is_legal_interval_for_alert(interval): """ Note: legal values for the interval on an alert are only 1, 10 or 60. This function verifies the value given is compatible with this demand. """ if not represents_int(interval): return False interval_int = int(interval) return interval_int == 1 or interval_int == 10 or interval_int == 60 def validate_list_description_length(description): if description is not None and len(description) > 140: return_error("Error: Description given is too long. Description must be 140 characters or shorter") def validate_update_list_args(method, description): if not (method == "Add" or method == "Remove"): return_error("Error: Method given is illegal. Method must be 'Add' or 'Remove'") validate_list_description_length(description) def validate_create_list_args(list_type, description): if not is_legal_list_type(list_type): return_error(f"Error: {list_type} is not a legal type for a list. Legal types are IP, String, Country or Wildcard") validate_list_description_length(description) def validate_alert_args(siteName, long_name, tag_name, interval, threshold, enabled, action): if not represents_int(threshold): return_error(f"Error: {threshold} is not a valid threshold value. Threshold must be an integer") if not is_legal_interval_for_alert(interval): return_error(f"Error: {interval} is not a valid interval value. Interval value must be 1, 10 or 60") if len(long_name) < 3 or len(long_name) > 25: return_error("Error: Illegal value for long_name argument - long_name must be between 3 and 25 characters long") if not (enabled.lower() == "true" or enabled.lower() == "false"): return_error("Error: Illegal value for 'enabled' argument - value must be 'True' or 'False'") if not (action == "info" or action == "flagged"): return_error("Error: Illegal value for 'action' argument - value must be 'info' or 'flagged'") def validate_get_events_args(from_time, until_time, sort, limit, page, action, ip, status): if from_time is not None and not represents_int(str(from_time)): return_error("Error: from_time must be an integer.") if until_time is not None and not represents_int(str(until_time)): return_error("Error: until_time must be an integer.") if sort is not None and not (sort == "asc" or sort == "desc"): return_error("Error: sort value must be 'asc' or 'desc'.") if limit is not None and (not represents_int(str(limit)) or int(limit) < 0 or int(limit) > 1000): return_error("Error: limit must be an integer, larger than 0 and at most 1000") if action is not None and not (action == "flagged" or action == "info"): return_error("Error: action value must be 'flagged' or 'info'") if ip is not None and not is_ip_valid(str(ip)): return_error("Error: illegal value for 'ip' argument. Must be a valid ip address") if status is not None and not (status == "active" or status == "expired"): return_error("Error: status value must be 'active' or 'expired'") if page is not None and not represents_int(str(page)): return_error("Error: page must be an integer.") def create_get_event_data_from_args(from_time, until_time, sort, since_id, max_id, limit, page, action, tag, ip, status): get_events_request_data = {} if from_time is not None: get_events_request_data["from"] = int(from_time) if until_time is not None: get_events_request_data["until"] = int(until_time) if sort is not None: get_events_request_data["sort"] = sort if since_id is not None: get_events_request_data["since_id"] = since_id if max_id is not None: get_events_request_data["max_id"] = max_id if limit is not None: get_events_request_data["limit"] = int(limit) if page is not None: get_events_request_data["page"] = int(page) if action is not None: get_events_request_data["action"] = action if tag is not None: get_events_request_data["tag"] = tag if ip is not None: get_events_request_data["ip"] = ip if status is not None: get_events_request_data["status"] = status return get_events_request_data def event_entry_context_from_response(response_data): entry_context = { "ID": response_data.get("id", ""), "Timestamp": response_data.get("timestamp", ""), "Source": response_data.get("source", ""), "Action": response_data.get("action", ""), "Reasons": response_data.get("reasons", ""), "RemoteCountryCode": response_data.get("remoteCountryCode", ""), "RemoteHostname": response_data.get("RemoteHostname", ""), "UserAgents": response_data.get("userAgents", ""), "RequestCount": response_data.get("requestCount", ""), "TagCount": response_data.get("tagCount", ""), "Window": response_data.get("window", ""), "DateExpires": response_data.get("expires", ""), "ExpiredBy": response_data.get("expiredBy", ""), } return entry_context def adjust_event_human_readable(entry_context_with_spaces, entry_context): """Change keys in human readable data to match the headers.""" entry_context_with_spaces["ID"] = entry_context.get("ID", "") def validate_fetch_requests_args(page, limit): if limit is not None and (not represents_int(limit) or int(limit) < 0 or int(limit) > 1000): return_error("Error: limit must be an integer, larger than 0 and at most 1000") if page is not None and not represents_int(page): return_error("Error: page must be an integer") def request_entry_context_from_response(response_data): entry_context = { "ID": response_data.get("id", ""), "ServerHostName": response_data.get("serverHostName", ""), "RemoteIP": response_data.get("remoteIP", ""), "RemoteHostname": response_data.get("RemoteHostname", ""), "RemoteCountryCode": response_data.get("remoteCountryCode", ""), "UserAgent": response_data.get("userAgent", ""), "Timestamp": response_data.get("timestamp", ""), "Method": response_data.get("method", ""), "ServerName": response_data.get("serverName", ""), "Protocol": response_data.get("protocol", ""), "Path": response_data.get("path", ""), "URI": response_data.get("uri", ""), "ResponseCode": response_data.get("responseCode", ""), "ResponseSize": response_data.get("responseSize", ""), "ResponseMillis": response_data.get("responseMillis", ""), "AgentResponseCode": response_data.get("agentResponseCode", ""), "Tags": response_data.get("tags", ""), } return entry_context def adjust_request_human_readable(entry_context_with_spaces, entry_context): """Change keys in human readable data to match the headers.""" entry_context_with_spaces["ID"] = entry_context.get("ID", "") entry_context_with_spaces["URI"] = entry_context.get("URI", "") entry_context_with_spaces["Remote IP"] = entry_context.get("RemoteIP", "") def list_entry_context_from_response(response_data): entry_context = { "ID": response_data.get("id", ""), "Name": response_data.get("name", ""), "Type": response_data.get("type", ""), "Entries": response_data.get("entries", ""), "Description": response_data.get("description", ""), "CreatedBy": response_data.get("createdBy", ""), "CreatedDate": response_data.get("created", ""), "UpdatedDate": response_data.get("updated", ""), } return entry_context def adjust_list_human_readable(entry_context_with_spaces, entry_context): """Change keys in human readable data to match the headers.""" entry_context_with_spaces["ID"] = entry_context.get("ID", "") def alert_entry_context_from_response(response_data): entry_context = { "ID": response_data.get("id", ""), "LongName": response_data.get("longName", ""), "SiteID": response_data.get("siteId", ""), "TagName": response_data.get("tagName", ""), "Interval": response_data.get("interval", ""), "Threshold": response_data.get("threshold", ""), "BlockDurationSeconds": response_data.get("blockDurationSeconds", ""), "SkipNotifications": response_data.get("skipNotifications", ""), "Enabled": response_data.get("enabled", ""), "Action": response_data.get("action", ""), "CreatedDate": response_data.get("created", ""), } return entry_context def adjust_alert_human_readable(entry_context_with_spaces, entry_context): """Change keys in human readable data to match the headers.""" entry_context_with_spaces["Interval (In Minutes)"] = entry_context_with_spaces.get("Interval", "") entry_context_with_spaces["ID"] = entry_context.get("ID", "") entry_context_with_spaces["Site ID"] = entry_context.get("siteID", "") def check_ip_is_valid(ip): if not is_ip_valid(ip): return_error(f"Error: {ip} is invalid IP. Please enter a valid IP address") def gen_entries_data_for_update_list_request(entries_list, method): """Using the recieved args, generates the data object required by the API in order to update a list (site or corp alike). Args: entries_list (list): a list containing IP addresses method (string): The method we want to apply on the entries, either 'Add' or 'Remove'. States if the IPs should be added or removed to the site/corp list. Returns: dict. Contains additions and deletions list with the entries we want to act on. """ entries = {"additions": [], "deletions": []} # type: Dict entries_list_in_list_format = entries_list.split(",") if method == "Add": entries["additions"] = entries_list_in_list_format else: entries["deletions"] = entries_list_in_list_format return entries def gen_context_for_add_to_whitelist_or_blacklist(response_data): full_data = [] for data in response_data: full_data.append( { "ID": data.get("id", ""), "Note": data.get("note", ""), "Source": data.get("source", ""), "CreatedBy": data.get("createdBy", ""), "CreatedDate": data.get("created", ""), "ExpiryDate": data.get("expires", ""), } ) return full_data def gen_human_readable_for_add_to_whitelist_or_blacklist(ip_context): human_readable = [] for context in ip_context: human_readable.append( { "Note": context["Note"], "Source": context["Source"], "Expiration date": context["ExpiryDate"] if context["ExpiryDate"] else "Not Set", } ) return human_readable def add_ip_to_whitelist_or_blacklist(url, ip, note, expires=None): res_list = [] error_list = [] for single_ip in argToList(ip): try: check_ip_is_valid(single_ip) data = {"source": single_ip, "note": note} if expires is not None: data["expires"] = expires res_list.append(http_request("PUT", url, data=data)) except SystemExit: # handle exceptions in return_error pass except Exception as e: error_list.append(f"failed adding ip: {single_ip} to balcklist error: {e}") demisto.error(f"failed adding ip: {single_ip} to balcklist\n{traceback.format_exc()}") return res_list, error_list def get_all_sites_in_corp(): get_sites_request_response = get_sites() data_of_sites_in_corp = get_sites_request_response.get("data", []) return data_of_sites_in_corp def get_list_of_all_site_names_in_corp(): data_of_sites_in_corp = get_all_sites_in_corp() list_of_all_sites_names_in_corp = [] for site_data in data_of_sites_in_corp: site_name = site_data["name"] list_of_all_sites_names_in_corp.append(site_name) return list_of_all_sites_names_in_corp def get_list_of_site_names_to_fetch(): list_of_site_names_to_fetch = None if SITES_TO_FETCH: list_of_site_names_to_fetch = SITES_TO_FETCH.split(",") else: list_of_site_names_to_fetch = get_list_of_all_site_names_in_corp() return list_of_site_names_to_fetch def remove_milliseconds_from_iso(date_in_iso_format): date_parts_arr = date_in_iso_format.split(".") date_in_iso_without_milliseconds = date_parts_arr[0] return date_in_iso_without_milliseconds def get_events_from_given_sites(list_of_site_names_to_fetch, desired_from_time_in_posix): events_from_given_sites = [] # type: List[Any] for site_name in list_of_site_names_to_fetch: fetch_from_site_response_json = get_events(siteName=site_name, from_time=desired_from_time_in_posix) events_fetched_from_site = fetch_from_site_response_json.get("data", []) events_from_given_sites.extend(events_fetched_from_site) return events_from_given_sites def datetime_to_posix_without_milliseconds(datetime_object): timestamp_in_unix_millisecond = date_to_timestamp(datetime_object, "datetime.datetime") posix_with_ms = timestamp_in_unix_millisecond posix_without_ms = str(posix_with_ms).split(",")[0] return posix_without_ms """COMMANDS""" def test_module(): try: url = SERVER_URL + "corps" http_request("GET", url) except Exception as e: raise Exception(e) demisto.results("ok") def create_corp_list(list_name, list_type, entries_list, description=None): """This method sends a request to the Signal Sciences API to create a new corp list. Note: Illegal entries (not compatible with the type) will result in a 404. They will be handled by the http_request function. Args: list_name (string): A name for the newly created list. list_type (string): The desired type for the newly created list. entries_list (list): A list of entries, consistent with the given type. description (string): A description for the newly created list. Returns: dict. The data returned from the Signal Sciences API in response to the request, loaded into a json. """ validate_create_list_args(list_type, description) url = SERVER_URL + CREATE_CORP_LIST_SUFFIX.format(CORPNAME) entries_list_in_list_format = entries_list.split(",") data_for_request = {"name": list_name.lower(), "type": list_type.lower(), "entries": entries_list_in_list_format} if description is not None: data_for_request["description"] = description new_list_data = http_request("POST", url, data=data_for_request) return new_list_data def create_corp_list_command(): args = demisto.args() response_data = create_corp_list(args["list_name"], args["list_type"], args["entries_list"], args.get("description", None)) entry_context = list_entry_context_from_response(response_data) entry_context_with_spaces = dict_keys_from_camelcase_to_spaces(entry_context) human_readable = tableToMarkdown( CREATE_CORP_LIST_TITLE.format(args["list_name"]), entry_context_with_spaces, headers=LIST_HEADERS, removeNull=True ) adjust_list_human_readable(entry_context_with_spaces, entry_context) return_outputs( raw_response=response_data, readable_output=human_readable, outputs={ "SigSciences.Corp.List(val.ID==obj.ID)": entry_context, }, ) def get_corp_list(list_id): url = SERVER_URL + ACCESS_CORP_LIST_SUFFIX.format(CORPNAME, list_id) list_data = http_request("GET", url) return list_data def get_corp_list_command(): args = demisto.args() response_data = get_corp_list(args["list_id"]) entry_context = list_entry_context_from_response(response_data) title = f"Found data about list with ID: {args['list_id']}" entry_context_with_spaces = dict_keys_from_camelcase_to_spaces(entry_context) adjust_list_human_readable(entry_context_with_spaces, entry_context) human_readable = tableToMarkdown(title, entry_context_with_spaces, headers=LIST_HEADERS, removeNull=True) return_outputs( raw_response=response_data, readable_output=human_readable, outputs={ "SigSciences.Corp.List(val.ID==obj.ID)": entry_context, }, ) def delete_corp_list(list_id): url = SERVER_URL + ACCESS_CORP_LIST_SUFFIX.format(CORPNAME, list_id) list_data = http_request("DELETE", url) return list_data def delete_corp_list_command(): args = demisto.args() response_data = delete_corp_list(args["list_id"]) demisto.results( { "Type": entryTypes["note"], "ContentsFormat": formats["markdown"], "Contents": response_data, "HumanReadable": DELETE_CORP_LIST_TITLE.format(args["list_id"]), } ) def update_corp_list(list_id, method, entries_list, description=None): validate_update_list_args(method, description) entries_in_update_format = gen_entries_data_for_update_list_request(entries_list, method) url = SERVER_URL + ACCESS_CORP_LIST_SUFFIX.format(CORPNAME, list_id) data_for_request = {"entries": entries_in_update_format} if description is not None: data_for_request["description"] = description response_data = http_request("PATCH", url, data=data_for_request) return response_data def update_corp_list_command(): args = demisto.args() response_data = update_corp_list(args["list_id"], args["method"], args["entries_list"], args.get("description", None)) entry_context = list_entry_context_from_response(response_data) entry_context_with_spaces = dict_keys_from_camelcase_to_spaces(entry_context) adjust_list_human_readable(entry_context_with_spaces, entry_context) human_readable = tableToMarkdown(UPDATE_LIST_TITLE, entry_context_with_spaces, headers=LIST_HEADERS, removeNull=True) return_outputs( raw_response=response_data, readable_output=human_readable, outputs={ "SigSciences.Corp.List(val.ID==obj.ID)": entry_context, }, ) def get_all_corp_lists(): url = SERVER_URL + CREATE_CORP_LIST_SUFFIX.format(CORPNAME) response_data = http_request("GET", url) return response_data def get_all_corp_lists_command(): response_data = get_all_corp_lists() list_of_corp_lists = response_data.get("data", []) corp_lists_contexts = [] for corp_list_data in list_of_corp_lists: cur_corp_list_context = list_entry_context_from_response(corp_list_data) corp_lists_contexts.append(cur_corp_list_context) sidedata = f"Number of corp lists in corp: {len(list_of_corp_lists)}" corp_lists_contexts_with_spaces = return_list_of_dicts_with_spaces(corp_lists_contexts) for i in range(len(corp_lists_contexts)): adjust_list_human_readable(corp_lists_contexts_with_spaces[i], corp_lists_contexts[i]) human_readable = tableToMarkdown( LIST_OF_CORP_LISTS_TITLE, corp_lists_contexts_with_spaces, headers=LIST_HEADERS, removeNull=True, metadata=sidedata ) return_outputs( raw_response=response_data, readable_output=human_readable, outputs={ "SigSciences.Corp.List(val.ID==obj.ID)": corp_lists_contexts, }, ) def get_events( siteName, from_time=None, until_time=None, sort=None, since_id=None, max_id=None, limit=None, page=None, action=None, tag=None, ip=None, status=None, ): validate_get_events_args(from_time, until_time, sort, limit, page, action, ip, status) url = SERVER_URL + GET_EVENTS_SUFFIX.format(CORPNAME, siteName) data_for_request = create_get_event_data_from_args( from_time, until_time, sort, since_id, max_id, limit, page, action, tag, ip, status ) events_data_response = http_request("GET", url, params_dict=data_for_request) return events_data_response def get_events_command(): args = demisto.args() response_data = get_events( args["siteName"], args.get("from_time", None), args.get("until_time", None), args.get("sort", None), args.get("since_id", None), args.get("max_id", None), args.get("limit", None), args.get("page", None), args.get("action", None), args.get("tag", None), args.get("ip", None), args.get("status", None), ) list_of_events = response_data.get("data", []) events_contexts = [] for event_data in list_of_events: cur_event_context = event_entry_context_from_response(event_data) events_contexts.append(cur_event_context) events_contexts_with_spaces = return_list_of_dicts_with_spaces(events_contexts) for i in range(len(events_contexts)): adjust_list_human_readable(events_contexts_with_spaces[i], events_contexts[i]) sidedata = f"Number of events in site: {len(list_of_events)}" human_readable = tableToMarkdown( LIST_OF_EVENTS_TITLE, events_contexts_with_spaces, removeNull=True, headers=EVENT_HEADERS, metadata=sidedata ) return_outputs( raw_response=response_data, readable_output=human_readable, outputs={ "SigSciences.Corp.Site.Event(val.ID==obj.ID)": events_contexts, }, ) def get_event_by_id(siteName, event_id): url = SERVER_URL + ACCESS_EVENT_SUFFIX.format(CORPNAME, siteName, event_id) event_data_response = http_request("GET", url) return event_data_response def get_event_by_id_command(): args = demisto.args() response_data = get_event_by_id(args["siteName"], args["event_id"]) entry_context = event_entry_context_from_response(response_data) title = f"Found data about event with ID: {args['event_id']}" entry_context_with_spaces = dict_keys_from_camelcase_to_spaces(entry_context) adjust_event_human_readable(entry_context_with_spaces, entry_context) human_readable = tableToMarkdown(title, entry_context_with_spaces, headers=EVENT_HEADERS, removeNull=True) return_outputs( raw_response=response_data, readable_output=human_readable, outputs={ "SigSciences.Corp.Site.Event(val.ID==obj.ID)": entry_context, }, ) def expire_event(siteName, event_id): url = SERVER_URL + EXPIRE_EVENT_SUFFIX.format(CORPNAME, siteName, event_id) event_data_response = http_request("POST", url) return event_data_response def expire_event_command(): args = demisto.args() response_data = expire_event(args["siteName"], args["event_id"]) demisto.results( { "Type": entryTypes["note"], "ContentsFormat": formats["markdown"], "Contents": response_data, "HumanReadable": EXPIRE_EVENT_TITLE.format(args["event_id"]), } ) def get_requests(siteName, page, limit, query): url = SERVER_URL + GET_REQUESTS_SUFFIX.format(CORPNAME, siteName) validate_fetch_requests_args(page, limit) data_for_request = {} if page is not None: data_for_request["page"] = page if limit is not None: data_for_request["limit"] = limit if query is not None: data_for_request["q"] = query requests_data_response = http_request("GET", url, data=data_for_request) return requests_data_response def get_requests_command(): args = demisto.args() response_data = get_requests(args["siteName"], args.get("page", None), args.get("limit", None), args.get("query", None)) list_of_requests = response_data.get("data", []) requests_contexts = [] for request_data in list_of_requests: cur_request_context = request_entry_context_from_response(request_data) requests_contexts.append(cur_request_context) requests_contexts_with_spaces = return_list_of_dicts_with_spaces(requests_contexts) for i in range(len(requests_contexts)): adjust_list_human_readable(requests_contexts_with_spaces[i], requests_contexts[i]) sidedata = f"Number of requests in site: {len(list_of_requests)}" human_readable = tableToMarkdown( LIST_OF_REQUESTS_TITLE, requests_contexts_with_spaces, headers=REQUEST_HEADER, removeNull=True, metadata=sidedata ) return_outputs( raw_response=response_data, readable_output=human_readable, outputs={ "SigSciences.Corp.Site.Request(val.ID==obj.ID)": requests_contexts, }, ) def get_request_by_id(siteName, request_id): url = SERVER_URL + ACCESS_REQUEST_SUFFIX.format(CORPNAME, siteName, request_id) request_data_response = http_request("GET", url) return request_data_response def get_request_by_id_command(): args = demisto.args() response_data = get_request_by_id(args["siteName"], args["request_id"]) entry_context = request_entry_context_from_response(response_data) title = f"Found data about request with ID: {args['request_id']}" entry_context_with_spaces = dict_keys_from_camelcase_to_spaces(entry_context) adjust_request_human_readable(entry_context_with_spaces, entry_context) human_readable = tableToMarkdown(title, entry_context_with_spaces, headers=REQUEST_HEADER, removeNull=True) return_outputs( raw_response=response_data, readable_output=human_readable, outputs={ "SigSciences.Corp.Site.Request(val.ID==obj.ID)": entry_context, }, ) def create_site_list(siteName, list_name, list_type, entries_list, description=None): validate_create_list_args(list_type, description) url = SERVER_URL + SITE_CREATE_LIST_SUFFIX.format(CORPNAME, siteName) entries_list_in_list_format = entries_list.split(",") data_for_request = {"name": list_name.lower(), "type": list_type.lower(), "entries": entries_list_in_list_format} if description is not None: data_for_request["description"] = description new_list_data = http_request("POST", url, data=data_for_request) return new_list_data def create_site_list_command(): args = demisto.args() response_data = create_site_list( args["siteName"], args["list_name"], args["list_type"], args["entries_list"], args.get("description", None) ) entry_context = list_entry_context_from_response(response_data) entry_context_with_spaces = dict_keys_from_camelcase_to_spaces(entry_context) adjust_list_human_readable(entry_context_with_spaces, entry_context) human_readable = tableToMarkdown( CREATE_SITE_LIST_TITLE.format(args["list_name"]), entry_context_with_spaces, headers=LIST_HEADERS, removeNull=True ) return_outputs( raw_response=response_data, readable_output=human_readable, outputs={ "SigSciences.Corp.Site.List(val.ID==obj.ID)": entry_context, }, ) def get_site_list(siteName, list_id): url = SERVER_URL + SITE_ACCESS_LIST_SUFFIX.format(CORPNAME, siteName, list_id) list_data = http_request("GET", url) return list_data def get_site_list_command(): args = demisto.args() response_data = get_site_list(args["siteName"], args["list_id"]) entry_context = list_entry_context_from_response(response_data) entry_context_with_spaces = dict_keys_from_camelcase_to_spaces(entry_context) adjust_list_human_readable(entry_context_with_spaces, entry_context) title = f"Found data about list with ID: {args['list_id']}" human_readable = tableToMarkdown(title, entry_context_with_spaces, headers=LIST_HEADERS, removeNull=True) return_outputs( raw_response=response_data, readable_output=human_readable, outputs={ "SigSciences.Corp.Site.List(val.ID==obj.ID)": entry_context, }, ) def delete_site_list(siteName, list_id): url = SERVER_URL + SITE_ACCESS_LIST_SUFFIX.format(CORPNAME, siteName, list_id) list_data = http_request("DELETE", url) return list_data def delete_site_list_command(): args = demisto.args() response_data = delete_site_list(args["siteName"], args["list_id"]) demisto.results( { "Type": entryTypes["note"], "ContentsFormat": formats["markdown"], "Contents": response_data, "HumanReadable": DELETE_SITE_LIST_TITLE.format(args["list_id"]), } ) def update_site_list(siteName, list_id, method, entries_list, description=None): validate_update_list_args(method, description) entries_in_update_format = gen_entries_data_for_update_list_request(entries_list, method) url = SERVER_URL + SITE_ACCESS_LIST_SUFFIX.format(CORPNAME, siteName, list_id) data_for_request = {"entries": entries_in_update_format} if description is not None: data_for_request["description"] = description response_data = http_request("PATCH", url, data=data_for_request) return response_data def update_site_list_command(): args = demisto.args() response_data = update_site_list( args["siteName"], args["list_id"], args["method"], args["entries_list"], args.get("description", None) ) entry_context = list_entry_context_from_response(response_data) entry_context_with_spaces = dict_keys_from_camelcase_to_spaces(entry_context) adjust_list_human_readable(entry_context_with_spaces, entry_context) human_readable = tableToMarkdown(UPDATE_LIST_TITLE, entry_context_with_spaces, headers=LIST_HEADERS, removeNull=True) return_outputs( raw_response=response_data, readable_output=human_readable, outputs={ "SigSciences.Corp.Site.List(val.ID==obj.ID)": entry_context, }, ) def get_all_site_lists(siteName): url = SERVER_URL + SITE_CREATE_LIST_SUFFIX.format(CORPNAME, siteName) response_data = http_request("GET", url) return response_data def get_all_site_lists_command(): args = demisto.args() response_data = get_all_site_lists(args["siteName"]) list_of_site_lists = response_data.get("data", []) site_lists_contexts = [] for site_list_data in list_of_site_lists: cur_site_context = list_entry_context_from_response(site_list_data) site_lists_contexts.append(cur_site_context) site_lists_contexts_with_spaces = return_list_of_dicts_with_spaces(site_lists_contexts) for i in range(len(site_lists_contexts)): adjust_list_human_readable(site_lists_contexts_with_spaces[i], site_lists_contexts[i]) sidedata = f"Number of site lists in site: {len(list_of_site_lists)}" human_readable = tableToMarkdown( LIST_OF_SITE_LISTS_TITLE, site_lists_contexts_with_spaces, headers=LIST_HEADERS, removeNull=True, metadata=sidedata ) return_outputs( raw_response=response_data, readable_output=human_readable, outputs={ "SigSciences.Corp.Site.List(val.ID==obj.ID)": site_lists_contexts, }, ) def add_alert(siteName, long_name, tag_name, interval, threshold, enabled, action): validate_alert_args(siteName, long_name, tag_name, interval, threshold, enabled, action) url = SERVER_URL + SITE_CREATE_ALERT_SUFFIX.format(CORPNAME, siteName) data_for_request = { "tagName": tag_name, "longName": long_name, "interval": int(interval), "threshold": int(threshold), "enabled": bool(enabled), "action": action, } response_data = http_request("POST", url, data=data_for_request) return response_data def add_alert_command(): args = demisto.args() response_data = add_alert( args["siteName"], args["long_name"], args["tag_name"], args["interval"], args["threshold"], args["enabled"], args["action"], ) entry_context = alert_entry_context_from_response(response_data) entry_context_with_spaces = dict_keys_from_camelcase_to_spaces(entry_context) # changing key of Interval to Interval (In Minutes) for human readable adjust_alert_human_readable(entry_context_with_spaces, entry_context) human_readable = tableToMarkdown(ADD_ALERT_TITLE, entry_context_with_spaces, headers=ALERT_HEADERS, removeNull=True) return_outputs( raw_response=response_data, readable_output=human_readable, outputs={ "SigSciences.Corp.Site.Alert(val.ID==obj.ID)": entry_context, }, ) def get_alert(siteName, alert_id): url = SERVER_URL + SITE_ACCESS_ALERT_SUFFIX.format(CORPNAME, siteName, alert_id) response_data = http_request("GET", url) return response_data def get_alert_command(): args = demisto.args() response_data = get_alert(args["siteName"], args["alert_id"]) entry_context = alert_entry_context_from_response(response_data) entry_context_with_spaces = dict_keys_from_camelcase_to_spaces(entry_context) # changing key of Interval to Interval (In Minutes) for human readable adjust_alert_human_readable(entry_context_with_spaces, entry_context) title = f"Data found for alert id: {args['alert_id']}" human_readable = tableToMarkdown(title, entry_context_with_spaces, headers=ALERT_HEADERS, removeNull=True) return_outputs( raw_response=response_data, readable_output=human_readable, outputs={ "SigSciences.Corp.Site.Alert(val.ID==obj.ID)": entry_context, }, ) def delete_alert(siteName, alert_id): url = SERVER_URL + SITE_ACCESS_ALERT_SUFFIX.format(CORPNAME, siteName, alert_id) response_data = http_request("DELETE", url) return response_data def delete_alert_command(): args = demisto.args() response_data = delete_alert(args["siteName"], args["alert_id"]) title = f"Alert {args['alert_id']} deleted succesfully" demisto.results( {"Type": entryTypes["note"], "ContentsFormat": formats["markdown"], "Contents": response_data, "HumanReadable": title} ) def update_alert(siteName, alert_id, tag_name, long_name, interval, threshold, enabled, action): validate_alert_args(siteName, long_name, tag_name, interval, threshold, enabled, action) url = SERVER_URL + SITE_ACCESS_ALERT_SUFFIX.format(CORPNAME, siteName, alert_id) data_for_request = { "tagName": tag_name, "longName": long_name, "interval": int(interval), "threshold": int(threshold), "action": action, "enabled": bool(enabled), } request_response = http_request("PATCH", url, data=data_for_request) return request_response def update_alert_command(): args = demisto.args() response_data = update_alert( args["siteName"], args["alert_id"], args["tag_name"], args["long_name"], args["interval"], args["threshold"], args["enabled"], args["action"], ) title = f"Updated alert {args['alert_id']}. new values:" entry_context = alert_entry_context_from_response(response_data) entry_context_with_spaces = dict_keys_from_camelcase_to_spaces(entry_context) # changing key of Interval to Interval (In Minutes) for human readable adjust_alert_human_readable(entry_context_with_spaces, entry_context) human_readable = tableToMarkdown(title, entry_context_with_spaces, headers=ALERT_HEADERS, removeNull=True) return_outputs( raw_response=response_data, readable_output=human_readable, outputs={ "SigSciences.Corp.Site.Alert(val.ID==obj.ID)": entry_context, }, ) def get_all_alerts(siteName): url = SERVER_URL + SITE_CREATE_ALERT_SUFFIX.format(CORPNAME, siteName) response_data = http_request("GET", url) return response_data def get_all_alerts_command(): args = demisto.args() response_data = get_all_alerts(args["siteName"]) alerts_list = response_data.get("data", []) alerts_contexts = [] for alert_data in alerts_list: cur_alert_context = alert_entry_context_from_response(alert_data) alerts_contexts.append(cur_alert_context) alerts_contexts_with_spaces = return_list_of_dicts_with_spaces(alerts_contexts) # changing key of Interval to Interval (In Minutes) for human readable in all alert contexts for i in range(len(alerts_contexts)): adjust_alert_human_readable(alerts_contexts_with_spaces[i], alerts_contexts[i]) sidedata = f"Number of alerts in site: {len(alerts_list)}" return_outputs( raw_response=response_data, readable_output=tableToMarkdown( ALERT_LIST_TITLE, alerts_contexts_with_spaces, headers=ALERT_HEADERS, removeNull=True, metadata=sidedata ), outputs={ "SigSciences.Corp.Site.Alert(val.ID==obj.ID)": alerts_contexts, }, ) def get_whitelist(siteName): url = SERVER_URL + WHITELIST_SUFFIX.format(CORPNAME, siteName) site_whitelist = http_request("GET", url) return site_whitelist def get_whitelist_command(): """Get the whitelist data for siteName""" args = demisto.args() site_whitelist = get_whitelist(args["siteName"]) data = site_whitelist.get("data", []) whitelist_ips_contexts = gen_context_for_add_to_whitelist_or_blacklist(data) whitelist_ips_contexts_with_spaces = return_list_of_dicts_with_spaces(whitelist_ips_contexts) sidedata = f"Number of IPs in the Whitelist {len(data)}" return_outputs( raw_response=site_whitelist, readable_output=tableToMarkdown( WHITELIST_TITLE, whitelist_ips_contexts_with_spaces, WHITELIST_OR_BLACKLIST_HEADERS, removeNull=True, metadata=sidedata, ), outputs={ "SigSciences.Corp.Site.Whitelist(val.ID==obj.ID)": whitelist_ips_contexts, }, ) def get_blacklist(siteName): url = SERVER_URL + BLACKLIST_SUFFIX.format(CORPNAME, siteName) site_blacklist = http_request("GET", url) return site_blacklist def get_blacklist_command(): """Get blacklist data for siteName""" args = demisto.args() site_blacklist = get_blacklist(args["siteName"]) data = site_blacklist.get("data", []) blacklist_ips_contexts = gen_context_for_add_to_whitelist_or_blacklist(data) blacklist_ips_contexts_with_spaces = return_list_of_dicts_with_spaces(blacklist_ips_contexts) sidedata = f"Number of IPs in the Blacklist {len(data)}" return_outputs( raw_response=site_blacklist, readable_output=tableToMarkdown( BLACKLIST_TITLE, blacklist_ips_contexts_with_spaces, WHITELIST_OR_BLACKLIST_HEADERS, removeNull=True, metadata=sidedata, ), outputs={ "SigSciences.Corp.Site.Blacklist(val.ID==obj.ID)": blacklist_ips_contexts, }, ) def add_ip_to_whitelist(siteName, ip, note, expires=None): url = SERVER_URL + WHITELIST_SUFFIX.format(CORPNAME, siteName) return add_ip_to_whitelist_or_blacklist(url, ip, note, expires) def add_ip_to_whitelist_command(): """Add an ip to the whitelist""" args = demisto.args() response_data, errors_data = add_ip_to_whitelist(args["siteName"], args["ip"], args["note"], args.get("expires", None)) if response_data: whitelist_ip_context = gen_context_for_add_to_whitelist_or_blacklist(response_data) human_readable = gen_human_readable_for_add_to_whitelist_or_blacklist(whitelist_ip_context) return_outputs( raw_response=response_data, readable_output=tableToMarkdown( ADD_IP_TO_WHITELIST_TITLE, human_readable, headers=ADD_IP_HEADERS, removeNull=True, metadata=IP_ADDED_TO_WHITELIST_TITLE.format(args["ip"]), ), outputs={ "SigSciences.Corp.Site.Whitelist(val.ID==obj.ID)": whitelist_ip_context, }, ) if errors_data: return_error("\n".join(errors_data)) def add_ip_to_blacklist(siteName, ip, note, expires=None): url = SERVER_URL + BLACKLIST_SUFFIX.format(CORPNAME, siteName) return add_ip_to_whitelist_or_blacklist(url, ip, note, expires) def add_ip_to_blacklist_command(): """Add an ip to the blacklist""" args = demisto.args() response_data, errors_data = add_ip_to_blacklist(args["siteName"], args["ip"], args["note"], args.get("expires", None)) if response_data: blacklist_ip_context = gen_context_for_add_to_whitelist_or_blacklist(response_data) human_readable = gen_human_readable_for_add_to_whitelist_or_blacklist(blacklist_ip_context) return_outputs( raw_response=response_data, readable_output=tableToMarkdown( ADD_IP_TO_BLACKLIST_TITLE, human_readable, headers=ADD_IP_HEADERS, removeNull=True, metadata=IP_ADDED_TO_BLACKLIST_TITLE.format(args["ip"]), ), outputs={ "SigSciences.Corp.Site.Blacklist(val.ID==obj.ID)": blacklist_ip_context, }, ) if errors_data: return_error("/n".join(errors_data)) def whitelist_remove_ip(siteName, ip): check_ip_is_valid(ip) site_whitelist = get_whitelist(siteName) data = site_whitelist.get("data", []) for item in data: if item.get("source", "") == ip: url = SERVER_URL + DELETE_WHITELIST_IP_SUFFIX.format(CORPNAME, siteName, item.get("id", "")) res = http_request("DELETE", url) if "res" not in locals(): return_error(f"The IP {ip} was not found on the Whitelist") return site_whitelist def whitelist_remove_ip_command(): """Remove an ip from the whitelist""" args = demisto.args() response_data = whitelist_remove_ip(args["siteName"], args["IP"]) demisto.results( { "Type": entryTypes["note"], "ContentsFormat": formats["markdown"], "Contents": response_data, "HumanReadable": WHITELIST_REMOVE_IP_TITLE.format(args["IP"]), } ) def blacklist_remove_ip(siteName, ip): check_ip_is_valid(ip) site_blacklist = get_blacklist(siteName) data = site_blacklist.get("data", []) for item in data: if item.get("source", "") == ip: url = SERVER_URL + DELETE_BLACKLIST_IP_SUFFIX.format(CORPNAME, siteName, item.get("id", "")) res = http_request("DELETE", url) if "res" not in locals(): return_error(f"The IP {ip} was not found on the Blacklist") return site_blacklist def blacklist_remove_ip_command(): """Remove an ip from the blacklist""" args = demisto.args() response_data = blacklist_remove_ip(args["siteName"], args["IP"]) demisto.results( { "Type": entryTypes["note"], "ContentsFormat": formats["markdown"], "Contents": response_data, "HumanReadable": BLACKLIST_REMOVE_IP_TITLE.format(args["IP"]), } ) def get_sites(): url = SERVER_URL + GET_SITES_SUFFIX.format(CORPNAME) res = http_request("GET", url) return res def get_sites_command(): """Get the sites list""" res = get_sites() data = res.get("data", []) outputs = [] for item in data: output = {} output["Name"] = item.get("name", "") output["CreatedDate"] = item.get("created", "") outputs.append(output) outputs_with_spaces = return_list_of_dicts_with_spaces(outputs) return_outputs( raw_response=res, readable_output=tableToMarkdown(SITES_LIST_TITLE, outputs_with_spaces, headers=GET_SITE_HEADERS, removeNull=True), outputs={ "SigSciences.Sites(val.Name==obj.Name)": outputs, }, ) def fetch_incidents(): now_utc = datetime.utcnow() most_recent_event_time = "" last_run_data = demisto.getLastRun() if last_run_data: last_run_time = last_run_data["time"] else: date_time_interval_ago = now_utc - timedelta(minutes=int(FETCH_INTERVAL)) date_time_interval_ago_posix = datetime_to_posix_without_milliseconds(date_time_interval_ago) last_run_time = date_time_interval_ago_posix list_of_sites_to_fetch = get_list_of_site_names_to_fetch() events_array = get_events_from_given_sites(list_of_sites_to_fetch, last_run_time) incidents = [] for event in events_array: event_time = event["timestamp"] event_time = datetime.strptime(event_time[:-1], "%Y-%m-%dT%H:%M:%S") event_time = datetime_to_posix_without_milliseconds(event_time) if event_time > last_run_time: incidents.append( {"name": str(event["id"]) + " - SignalSciences", "occurred": event["timestamp"], "rawJSON": json.dumps(event)} ) if event_time > most_recent_event_time: most_recent_event_time = event_time demisto.incidents(incidents) demisto.setLastRun({"time": most_recent_event_time}) """ EXECUTION CODE """ def main() -> None: LOG(f"command is {demisto.command()}") try: if not re.match(r"[0-9a-z_.-]+", CORPNAME): raise ValueError("Corporation Name should match the pattern [0-9a-z_.-]+") if demisto.command() == "test-module": test_module() elif demisto.command() == "fetch-incidents": fetch_incidents() elif demisto.command() == "sigsci-get-whitelist": get_whitelist_command() elif demisto.command() == "sigsci-get-blacklist": get_blacklist_command() elif demisto.command() == "sigsci-whitelist-add-ip": add_ip_to_whitelist_command() elif demisto.command() == "sigsci-blacklist-add-ip": add_ip_to_blacklist_command() elif demisto.command() == "sigsci-whitelist-remove-ip": whitelist_remove_ip_command() elif demisto.command() == "sigsci-blacklist-remove-ip": blacklist_remove_ip_command() elif demisto.command() == "sigsci-get-sites": get_sites_command() elif demisto.command() == "sigsci-create-corp-list": create_corp_list_command() elif demisto.command() == "sigsci-get-corp-list": get_corp_list_command() elif demisto.command() == "sigsci-delete-corp-list": delete_corp_list_command() elif demisto.command() == "sigsci-update-corp-list": update_corp_list_command() elif demisto.command() == "sigsci-get-all-corp-lists": get_all_corp_lists_command() elif demisto.command() == "sigsci-create-site-list": create_site_list_command() elif demisto.command() == "sigsci-get-site-list": get_site_list_command() elif demisto.command() == "sigsci-delete-site-list": delete_site_list_command() elif demisto.command() == "sigsci-update-site-list": update_site_list_command() elif demisto.command() == "sigsci-get-all-site-lists": get_all_site_lists_command() elif demisto.command() == "sigsci-add-alert": add_alert_command() elif demisto.command() == "sigsci-get-alert": get_alert_command() elif demisto.command() == "sigsci-delete-alert": delete_alert_command() elif demisto.command() == "sigsci-update-alert": update_alert_command() elif demisto.command() == "sigsci-get-all-alerts": get_all_alerts_command() elif demisto.command() == "sigsci-get-events": get_events_command() elif demisto.command() == "sigsci-expire-event": expire_event_command() elif demisto.command() == "sigsci-get-event-by-id": get_event_by_id_command() elif demisto.command() == "sigsci-get-requests": get_requests_command() elif demisto.command() == "sigsci-get-request-by-id": get_request_by_id_command() except Exception as e: return_error(e) if __name__ in ("__main__", "__builtin__", "builtins"): main()