Skip to content

Commit

Permalink
Cyble enhancements (#35808)
Browse files Browse the repository at this point in the history
* Cyble enhancements (#35788)

* IOC Updates

* Module imports fixups

* Review changes

* Update Packs/CybleEventsV2/Integrations/CybleEventsV2/CybleEventsV2.yml

* Update Packs/CybleEventsV2/ReleaseNotes/1_0_4.md

---------

Co-authored-by: cyble-dev <[email protected]>
Co-authored-by: israelpoli <[email protected]>
  • Loading branch information
3 people committed Aug 8, 2024
1 parent 3cad4c5 commit e202181
Show file tree
Hide file tree
Showing 7 changed files with 143 additions and 115 deletions.
82 changes: 61 additions & 21 deletions Packs/CybleEventsV2/Integrations/CybleEventsV2/CybleEventsV2.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,13 @@

''' IMPORTS '''
import requests
from datetime import datetime, timezone
from datetime import datetime
import pytz
import urllib3
import json

UTC = pytz.UTC

# Disable insecure warnings
urllib3.disable_warnings()

Expand Down Expand Up @@ -113,9 +116,9 @@ def validate_input(args, is_iocs=False):
_start_date = datetime(1, 1, 1, 0, 0)
_end_date = datetime(1, 1, 1, 0, 0)

if limit <= 0 or limit > 1000:
if limit <= 0 or limit > 100:
raise ValueError(
f"The limit argument should contain a positive number, up to 1000, limit: {limit}")
f"The limit argument should contain a positive number, up to 100, limit: {limit}")

if _start_date > datetime.utcnow():
raise ValueError(
Expand All @@ -132,10 +135,10 @@ def validate_input(args, is_iocs=False):
if limit <= 0 or limit > LIMIT_EVENT_ITEMS:
raise ValueError(f"The limit argument should contain a positive number, up to 1000, limit: {limit}")

if _start_date > datetime.now(tz=timezone.utc):
if _start_date > datetime.now(tz=UTC):
raise ValueError(
f"Start date must be a date before or equal to {datetime.now(tz=timezone.utc).strftime(date_format)}")
if _end_date > datetime.now(tz=timezone.utc):
f"Start date must be a date before or equal to {datetime.now(tz=UTC).strftime(date_format)}")
if _end_date > datetime.now(tz=UTC):
raise ValueError(
f"End date must be a date before or equal to {args.get('end_date')}")
if _start_date > _end_date:
Expand Down Expand Up @@ -229,14 +232,19 @@ def format_incidents(alerts, hide_cvv_expiry):
alert['data_message']['data']['bank']['card']['cvv'] = "xxx"
alert['data_message']['data']['bank']['card']['expiry'] = "xx/xx/xxxx"

keyword = ""
if alert.get('metadata') and alert['metadata'].get('entity'):
if alert['metadata']['entity'].get('keyword') and alert['metadata']['entity']['keyword']['tag_name']:
keyword = alert['metadata']['entity']['keyword']['tag_name']

alert_details = {
"name": "Cyble Vision Alert on {}".format(alert['service']),
"event_type": "{}".format(alert['service']),
"severity": INCIDENT_SEVERITY.get(alert['severity'].lower()),
"alert_group_id": "{}".format(alert['alert_group_id']),
"event_id": "{}".format(alert['id']),
"data_message": json.dumps(alert['data_message']),
"keyword": "{}".format(alert['metadata']['entity']['keyword']['tag_name']),
"keyword": "{}".format(keyword),
"created_at": "{}".format(alert['created_at']),
"status": "{}".format(alert['status']),
"mirrorInstance": demisto.integrationInstance()
Expand Down Expand Up @@ -710,32 +718,64 @@ def cyble_fetch_iocs(client, method, token, args, url):
if args.get('end_date'):
input_params_alerts_iocs['endDate'] = args.get('end_date')

iocs = set_request(client, method, token, input_params_alerts_iocs, url)
response = set_request(client, method, token, input_params_alerts_iocs, url)

try:
lst_iocs = []
for ioc in iocs['result']:
for ioc in response['iocs']:

sources = []
behaviour_tags = []
target_countries = []
target_regions = []
target_industries = []
related_malwares = []
related_threat_actors = []

if ioc.get('sources'):
for source in ioc.get('sources'):
sources.append(source)

if ioc.get('behaviour_tags'):
for behaviour_tag in ioc.get('behaviour_tags'):
behaviour_tags.append(behaviour_tag)

if ioc.get('target_countries'):
for target_country in ioc.get('target_countries'):
target_countries.append(target_country)

if ioc.get('target_regions'):
for target_region in ioc.get('target_regions'):
target_regions.append(target_region)

lst_attack = []
lst_tags = []
if ioc.get('target_industries'):
for target_industry in ioc.get('target_industries'):
target_industries.append(target_industry)

for attack_details in ioc['attack_id']:
lst_attack.append(attack_details['attack_id'])
if ioc.get('related_malware'):
for related_malware in ioc.get('related_malware'):
related_malwares.append(related_malware)

for ioc_tags in ioc['ioc_tags']:
lst_tags.append(ioc_tags['name'])
if ioc.get('related_threat_actors'):
for related_threat_actor in ioc.get('related_threat_actors'):
related_threat_actors.append(related_threat_actor)

lst_iocs.append({'ioc': "{}".format(ioc['ioc']),
'ioc_type': "{}".format(ioc['ioc_type']),
'first_seen': "{}".format(ioc['first_seen']),
'last_seen': "{}".format(ioc['last_seen']),
'risk_rating': "{}".format(ioc['risk_rating']),
'confident_rating': "{}".format(ioc['confident_rating']),
'ioc_type': "{}".format(ioc['ioc_type']['name']),
'attack': f"{lst_attack}",
'tags': f"{lst_tags}"
'risk_score': "{}".format(ioc['risk_score']),
'confidence_rating': "{}".format(ioc['confidence_rating']),
'sources': f"{sources}",
'behaviour_tags': f"{behaviour_tags}",
'target_countries': f"{target_countries}",
'target_regions': f"{target_regions}",
'target_industries': f"{target_industries}",
'related_malware': f"{related_malwares}",
'related_threat_actors': f"{related_threat_actors}",
})
except Exception as e:
raise Exception(f"Error: [{e}] for response [{iocs}]")
raise Exception(f"Error: [{e}] for response [{response}]")

markdown = tableToMarkdown('Indicator of Compromise:', lst_iocs, )

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -103,11 +103,11 @@ script:
- Emai
- description: Returns records for the specified indicator value.
name: ioc
- defaultValue: '0'
- defaultValue: '1'
description: Returns records that starts from the given page number (the value of the form parameter) in the results list.
name: from
- defaultValue: '1'
description: Number of records to return (max 1000). Using a smaller limit will get faster responses.
description: Number of records to return (max 100). Using a smaller limit will get faster responses.
name: limit
- auto: PREDEFINED
defaultValue: last_seen
Expand Down Expand Up @@ -202,7 +202,7 @@ script:
type: String
- description: Retrieves a User Profile schema, which holds all of the user fields within the application. Used for outgoing-mapping through the Get Schema option.
name: get-mapping-fields
dockerimage: demisto/python3:3.10.13.80014
dockerimage: demisto/python3:3.11.9.107902
isfetch: true
runonce: false
script: '-'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,15 @@
"""

import json
from datetime import datetime, timezone, timedelta
from datetime import datetime, timedelta
import pytz

import pytest

import demistomock as demisto

UTC = pytz.UTC


def util_load_json(path):
with open("test_data/" + path, encoding='utf-8') as f:
Expand Down Expand Up @@ -120,10 +123,10 @@ def test_get_iocs(requests_mock, offset):
assert isinstance(response, list)
assert isinstance(response[0], dict)
assert response[0]['ioc'] == 'Indicator'
assert response[0]['last_seen'] == '2023-02-20 21:00:55'
assert response[0]['first_seen'] == '2023-02-20 21:00:55'
assert response[0]['ioc_type'] == 'some indicator type'
assert response[0]['risk_rating'] == 'Some Risk Rating'
assert response[0]['ioc_type'] == 'Some IOC Type'
assert response[0]['first_seen'] == '1722227702'
assert response[0]['last_seen'] == '1722472568'
assert response[0]['risk_score'] == '70'


def test_get_alert_group(requests_mock):
Expand Down Expand Up @@ -238,8 +241,8 @@ def test_limit_validate_input(capfd):
from CybleEventsV2 import validate_input

args = {
'start_date': datetime.now(tz=timezone.utc).strftime("%Y-%m-%dT%H:%M:%S%z"),
'end_date': datetime.now(tz=timezone.utc).strftime("%Y-%m-%dT%H:%M:%S%z"),
'start_date': datetime.now(tz=UTC).strftime("%Y-%m-%dT%H:%M:%S%z"),
'end_date': datetime.now(tz=UTC).strftime("%Y-%m-%dT%H:%M:%S%z"),
'from': '0',
'limit': '-1',
}
Expand All @@ -260,7 +263,7 @@ def test_limit_validate_ioc_input(capfd):
}
with capfd.disabled(), pytest.raises(ValueError,
match="The limit argument should contain a positive number,"
f" up to 1000, limit: {args.get('limit', '50')}"):
f" up to 100, limit: {args.get('limit', '50')}"):
validate_input(args=args, is_iocs=True)


Expand All @@ -284,8 +287,8 @@ def test_edate_validate_input(capfd):
from CybleEventsV2 import validate_input

args = {
'start_date': datetime.now(tz=timezone.utc).strftime("%Y-%m-%dT%H:%M:%S%z"),
'end_date': (datetime.now(tz=timezone.utc) + timedelta(days=4)).strftime("%Y-%m-%dT%H:%M:%S%z"),
'start_date': datetime.now(tz=UTC).strftime("%Y-%m-%dT%H:%M:%S%z"),
'end_date': (datetime.now(tz=UTC) + timedelta(days=4)).strftime("%Y-%m-%dT%H:%M:%S%z"),
'from': '0',
'limit': '1'
}
Expand All @@ -300,8 +303,8 @@ def test_date_validate_input(capfd):
from CybleEventsV2 import validate_input

args = {
'start_date': datetime.now(tz=timezone.utc).strftime("%Y-%m-%dT%H:%M:%S%z"),
'end_date': (datetime.now(tz=timezone.utc) - timedelta(days=4)).strftime("%Y-%m-%dT%H:%M:%S%z"),
'start_date': datetime.now(tz=UTC).strftime("%Y-%m-%dT%H:%M:%S%z"),
'end_date': (datetime.now(tz=UTC) - timedelta(days=4)).strftime("%Y-%m-%dT%H:%M:%S%z"),
'from': '0',
'limit': '1'
}
Expand Down Expand Up @@ -337,8 +340,8 @@ def test_offset_cyble_vision_fetch_detail(requests_mock, capfd):
args = {
'from': '-1',
'limit': 1,
'start_date': datetime.now(tz=timezone.utc).strftime("%Y-%m-%dT%H:%M:%S%z"),
'end_date': datetime.now(tz=timezone.utc).strftime("%Y-%m-%dT%H:%M:%S%z")
'start_date': datetime.now(tz=UTC).strftime("%Y-%m-%dT%H:%M:%S%z"),
'end_date': datetime.now(tz=UTC).strftime("%Y-%m-%dT%H:%M:%S%z")
}

url = "https://test.com/apollo/api/v1/y/alerts"
Expand Down Expand Up @@ -368,8 +371,8 @@ def test_get_alert_fetch(requests_mock):
args = {
'from': 1,
'limit': 1,
'start_date': datetime.now(tz=timezone.utc).strftime("%Y-%m-%dT%H:%M:%S%z"),
'end_date': datetime.now(tz=timezone.utc).strftime("%Y-%m-%dT%H:%M:%S%z")
'start_date': datetime.now(tz=UTC).strftime("%Y-%m-%dT%H:%M:%S%z"),
'end_date': datetime.now(tz=UTC).strftime("%Y-%m-%dT%H:%M:%S%z")
}

url = "https://test.com/apollo/api/v1/y/alerts"
Expand Down Expand Up @@ -400,8 +403,8 @@ def test_get_alert_fetch2(requests_mock):
args = {
'from': 1,
'limit': 1,
'start_date': datetime.now(tz=timezone.utc).strftime("%Y-%m-%dT%H:%M:%S%z"),
'end_date': datetime.now(tz=timezone.utc).strftime("%Y-%m-%dT%H:%M:%S%z")
'start_date': datetime.now(tz=UTC).strftime("%Y-%m-%dT%H:%M:%S%z"),
'end_date': datetime.now(tz=UTC).strftime("%Y-%m-%dT%H:%M:%S%z")
}

url = "https://test.com/apollo/api/v1/y/alerts"
Expand Down Expand Up @@ -451,8 +454,8 @@ def test_data_alert_invalidate_date(capfd):
from CybleEventsV2 import validate_input

args = {
'start_date': datetime.now(tz=timezone.utc).strftime("%Y-%m-%dT%H:%M"),
'end_date': (datetime.now(tz=timezone.utc) - timedelta(days=4)).strftime("%Y-%m-%dT%H:%M"),
'start_date': datetime.now(tz=UTC).strftime("%Y-%m-%dT%H:%M"),
'end_date': (datetime.now(tz=UTC) - timedelta(days=4)).strftime("%Y-%m-%dT%H:%M"),
'from': '0',
'limit': '1'
}
Expand All @@ -467,8 +470,8 @@ def test_data_alert_iocs_date(capfd):
from CybleEventsV2 import validate_input

args = {
'start_date': datetime.now(tz=timezone.utc).strftime("%Y-%m-%dT%H:%M"),
'end_date': (datetime.now(tz=timezone.utc) - timedelta(days=4)).strftime("%Y-%m-%dT%H:%M"),
'start_date': datetime.now(tz=UTC).strftime("%Y-%m-%dT%H:%M"),
'end_date': (datetime.now(tz=UTC) - timedelta(days=4)).strftime("%Y-%m-%dT%H:%M"),
'from': '0',
'limit': '1'
}
Expand Down
22 changes: 11 additions & 11 deletions Packs/CybleEventsV2/Integrations/CybleEventsV2/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,17 +60,17 @@ Fetch the indicators in the given timeline.

#### Input

| **Argument Name** | **Description** | **Required** |
|-------------------|--------------------------------------------------------------------------------------------------------------------------------------------|--------------|
| ioc_type | Returns records according to their type (Domain, FileHash-MD5, FileHash-SHA1, FileHash-SHA256, IPv4, IPv6, URL, Email). Default is Domain. | Optional |
| ioc | Returns records for the specified indicator value. | Optional |
| from | Returns records that starts from the given page number (the value of the form parameter) in the results list. Default is 0. | Optional |
| limit | Number of records to return (max 1000). Using a smaller limit will get faster responses. Default is 1. | Optional |
| sort_by | Sorting based on the column(last_seen,first_seen,ioc_type). Possible values are: last_seen, first_seen, ioc_type. Default is last_seen. | Optional |
| order | Sorting order for ioc either Ascending or Descending based on sort by. Default is desc. | Optional |
| tags | Returns records for the specified tags. | Optional |
| start_date | Timeline start date in the format "YYYY-MM-DD". Should be used with start_date as timeline range. | Optional |
| end_date | Timeline end date in the format "YYYY-MM-DD". Should be used with end_date as timeline range. | Optional |
| **Argument Name** | **Description** | **Required** |
|-------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------|--------------|
| ioc_type | Returns records according to their type (Domain, FileHash-MD5, FileHash-SHA1, FileHash-SHA256, IPv4, IPv6, URL, Email, Wallet-Address). Default is Domain. | Optional |
| ioc | Returns records for the specified indicator value. | Optional |
| from | Returns records that starts from the given page number (the value of the form parameter) in the results list. Default is 1. | Optional |
| limit | Number of records to return (max 100). Using a smaller limit will get faster responses. Default is 1. | Optional |
| sort_by | Sorting based on the column(last_seen,first_seen,ioc_type). Possible values are: last_seen, first_seen, ioc_type. Default is last_seen. | Optional |
| order | Sorting order for ioc either Ascending or Descending based on sort by. Default is desc. | Optional |
| tags | Returns records for the specified tags. | Optional |
| start_date | Timeline start date in the format "YYYY-MM-DD". Should be used with start_date as timeline range. | Optional |
| end_date | Timeline end date in the format "YYYY-MM-DD". Should be used with end_date as timeline range. | Optional |

#### Context Output

Expand Down
Loading

0 comments on commit e202181

Please sign in to comment.