Skip to content

Commit 36b07b3

Browse files
[client] handle too large items (opencti #12816)
1 parent 0d5b738 commit 36b07b3

File tree

6 files changed

+53
-13
lines changed

6 files changed

+53
-13
lines changed

pycti/api/opencti_api_connector.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ def list(self) -> Dict:
7979
push
8080
push_exchange
8181
push_routing
82+
dead_letter_routing
8283
}
8384
}
8485
}

pycti/utils/opencti_stix2.py

Lines changed: 30 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
import time
99
import traceback
1010
import uuid
11-
from typing import Any, Dict, List, Optional, Union
11+
from typing import Any, Dict, List, Optional, Tuple, Union
1212

1313
import datefinder
1414
import dateutil.parser
@@ -32,6 +32,7 @@
3232
STIX_CORE_OBJECTS,
3333
STIX_CYBER_OBSERVABLE_MAPPING,
3434
STIX_META_OBJECTS,
35+
OpenCTIStix2Utils,
3536
)
3637

3738
datefinder.ValueError = ValueError, OverflowError
@@ -196,7 +197,7 @@ def import_bundle_from_file(
196197
file_path: str,
197198
update: bool = False,
198199
types: List = None,
199-
) -> Optional[List]:
200+
) -> Optional[Tuple[list, list]]:
200201
"""import a stix2 bundle from a file
201202
202203
:param file_path: valid path to the file
@@ -221,7 +222,8 @@ def import_bundle_from_json(
221222
update: bool = False,
222223
types: List = None,
223224
work_id: str = None,
224-
) -> List:
225+
objects_max_refs: int = 0,
226+
) -> Tuple[list, list]:
225227
"""import a stix2 bundle from JSON data
226228
227229
:param json_data: JSON data
@@ -231,11 +233,13 @@ def import_bundle_from_json(
231233
:param types: list of stix2 types, defaults to None
232234
:type types: list, optional
233235
:param work_id work_id: str, optional
234-
:return: list of imported stix2 objects
235-
:rtype: List
236+
:param objects_max_refs: max deps amount of objects, reject object import if larger than configured amount
237+
:type objects_max_refs: int, optional
238+
:return: list of imported stix2 objects and a list of stix2 objects with too many deps
239+
:rtype: Tuple[List,List]
236240
"""
237241
data = json.loads(json_data)
238-
return self.import_bundle(data, update, types, work_id)
242+
return self.import_bundle(data, update, types, work_id, objects_max_refs)
239243

240244
def resolve_author(self, title: str) -> Optional[Identity]:
241245
if "fireeye" in title.lower() or "mandiant" in title.lower():
@@ -3060,7 +3064,8 @@ def import_bundle(
30603064
update: bool = False,
30613065
types: List = None,
30623066
work_id: str = None,
3063-
) -> List:
3067+
objects_max_refs: int = 0,
3068+
) -> Tuple[list, list]:
30643069
# Check if the bundle is correctly formatted
30653070
if "type" not in stix_bundle or stix_bundle["type"] != "bundle":
30663071
raise ValueError("JSON data type is not a STIX2 bundle")
@@ -3094,12 +3099,27 @@ def import_bundle(
30943099

30953100
# Import every element in a specific order
30963101
imported_elements = []
3102+
too_large_elements_bundles = []
30973103
for bundle in bundles:
30983104
for item in bundle["objects"]:
3099-
self.import_item(item, update, types, 0, work_id)
3100-
imported_elements.append({"id": item["id"], "type": item["type"]})
3105+
# If item is considered too large, meaning that it has a number of refs higher than inputted objects_max_refs, do not import it
3106+
nb_refs = OpenCTIStix2Utils.compute_object_refs_number(item)
3107+
if 0 < objects_max_refs <= nb_refs:
3108+
self.opencti.work.report_expectation(
3109+
work_id,
3110+
{
3111+
"error": "Too large element in bundle",
3112+
"source": "Element "
3113+
+ item["id"]
3114+
+ " is too large and couldn't be processed",
3115+
},
3116+
)
3117+
too_large_elements_bundles.append(item)
3118+
else:
3119+
self.import_item(item, update, types, 0, work_id)
3120+
imported_elements.append({"id": item["id"], "type": item["type"]})
31013121

3102-
return imported_elements
3122+
return imported_elements, too_large_elements_bundles
31033123

31043124
@staticmethod
31053125
def put_attribute_in_extension(

pycti/utils/opencti_stix2_splitter.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,7 @@ def enlist_element(
196196
)
197197
else:
198198
is_compatible = is_id_supported(item_id)
199+
199200
if is_compatible:
200201
self.elements.append(item)
201202
else:
@@ -262,7 +263,11 @@ def by_dep_size(elem):
262263
)
263264
)
264265

265-
return number_expectations, self.incompatible_items, bundles
266+
return (
267+
number_expectations,
268+
self.incompatible_items,
269+
bundles,
270+
)
266271

267272
@deprecated("Use split_bundle_with_expectations instead")
268273
def split_bundle(self, bundle, use_json=True, event_version=None) -> list:

pycti/utils/opencti_stix2_utils.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -233,3 +233,17 @@ def retrieveClassForMethod(
233233
if hasattr(attribute, method):
234234
return attribute
235235
return None
236+
237+
@staticmethod
238+
def compute_object_refs_number(entity: Dict):
239+
refs_number = 0
240+
for key in list(entity.keys()):
241+
if key.endswith("_refs") and entity[key] is not None:
242+
refs_number += len(entity[key])
243+
elif key.endswith("_ref"):
244+
refs_number += 1
245+
elif key == "external_references" and entity[key] is not None:
246+
refs_number += len(entity[key])
247+
elif key == "kill_chain_phases" and entity[key] is not None:
248+
refs_number += len(entity[key])
249+
return refs_number

tests/02-integration/entities/test_malware.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ def test_malware_import_with_sample_refs(api_client):
55
with open("tests/data/basicMalwareWithSample.json", "r") as content_file:
66
content = content_file.read()
77

8-
imported_malware_bundle = api_client.stix2.import_bundle_from_json(
8+
imported_malware_bundle, _ = api_client.stix2.import_bundle_from_json(
99
json_data=content
1010
)
1111
assert imported_malware_bundle is not None

tests/02-integration/utils/test_stix_crud.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ def test_entity_create(entity_class, api_stix, opencti_splitter):
2121
stix_object = stix_class(**class_data)
2222
bundle = Bundle(objects=[stix_object]).serialize()
2323
split_bundle = opencti_splitter.split_bundle(bundle, True, None)[0]
24-
bundles_sent = api_stix.import_bundle_from_json(split_bundle, False, None, None)
24+
bundles_sent, _ = api_stix.import_bundle_from_json(split_bundle, False, None, None)
2525

2626
assert len(bundles_sent) == 1
2727
assert bundles_sent[0]["id"] == stix_object["id"]

0 commit comments

Comments
 (0)