Skip to content

Commit 89d80ca

Browse files
author
Samuel Hassine
committed
[client/examples] End of work about indicators/observables
1 parent a1fd916 commit 89d80ca

5 files changed

+155
-16
lines changed

examples/create_campaign_attributed-to_intrusion_set.py

-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
# coding: utf-8
22

3-
import datetime
4-
53
from dateutil.parser import parse
64
from pycti import OpenCTIApiClient
75

+70
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
# coding: utf-8
2+
3+
import datetime
4+
5+
from dateutil.parser import parse
6+
from pycti import OpenCTIApiClient
7+
8+
# Variables
9+
api_url = 'https://demo.opencti.io'
10+
api_token = 'c2d944bb-aea6-4bd6-b3d7-6c10451e2256'
11+
12+
# OpenCTI initialization
13+
opencti_api_client = OpenCTIApiClient(api_url, api_token)
14+
15+
# Define the date
16+
date = parse('2019-12-01').strftime('%Y-%m-%dT%H:%M:%SZ')
17+
18+
# Create the Campaign
19+
campaign = opencti_api_client.campaign.create(
20+
name='My new Campaign',
21+
description='Large SpearPhishing and intrusions followed by ransomware',
22+
objective='Financial gain',
23+
first_seen=date,
24+
last_seen=date,
25+
update=True
26+
)
27+
print(campaign)
28+
29+
# Create the indicator
30+
indicator = opencti_api_client.indicator.create(
31+
name='C2 server of the new campaign',
32+
description='This is the C2 server of the campaign',
33+
pattern_type='stix',
34+
indicator_pattern="[domain-name:value = 'www.5z8.info' AND domain-name:resolves_to_refs[*].value = '198.51.100.1/32']",
35+
main_observable_type='IPv4-Addr',
36+
valid_from=date
37+
)
38+
print(indicator)
39+
40+
# Create the observables (optional)
41+
observable_1 = opencti_api_client.stix_observable.create(
42+
type='Domain',
43+
observable_value='www.5z8.info'
44+
)
45+
observable_2 = opencti_api_client.stix_observable.create(
46+
type='IPv4-Addr',
47+
observable_value='198.51.100.1'
48+
)
49+
# Create the relation between observables and the indicator
50+
opencti_api_client.indicator.add_stix_observable(
51+
id=indicator['id'],
52+
stix_observable_id=observable_1['id']
53+
)
54+
opencti_api_client.indicator.add_stix_observable(
55+
id=indicator['id'],
56+
stix_observable_id=observable_2['id']
57+
)
58+
59+
# Create the relation
60+
relation = opencti_api_client.stix_relation.create(
61+
fromType='Indicator',
62+
fromId=indicator['id'],
63+
toType='Campaign',
64+
toId=campaign['id'],
65+
relationship_type='indicates',
66+
first_seen=date,
67+
last_seen=date,
68+
description='This is the C2 server of the campaign.'
69+
)
70+
print(relation)

pycti/entities/opencti_indicator.py

+57-2
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,7 @@ def create_raw(self, **kwargs):
206206
name = kwargs.get('name', None)
207207
description = kwargs.get('description', None)
208208
indicator_pattern = kwargs.get('indicator_pattern', None)
209+
main_observable_type = kwargs.get('main_observable_type', None)
209210
pattern_type = kwargs.get('pattern_type', None)
210211
valid_from = kwargs.get('valid_from', None)
211212
valid_until = kwargs.get('valid_until', None)
@@ -216,7 +217,7 @@ def create_raw(self, **kwargs):
216217
modified = kwargs.get('modified', None)
217218
created_by_ref = kwargs.get('createdByRef', None)
218219

219-
if name is not None and indicator_pattern is not None:
220+
if name is not None and indicator_pattern is not None and main_observable_type is not None:
220221
self.opencti.log('info', 'Creating Indicator {' + name + '}.')
221222
query = """
222223
mutation IndicatorAdd($input: IndicatorAddInput) {
@@ -230,6 +231,7 @@ def create_raw(self, **kwargs):
230231
'name': name,
231232
'description': description,
232233
'indicator_pattern': indicator_pattern,
234+
'main_observable_type': main_observable_type,
233235
'pattern_type': pattern_type,
234236
'valid_from': valid_from,
235237
'valid_until': valid_until,
@@ -243,7 +245,10 @@ def create_raw(self, **kwargs):
243245
})
244246
return self.opencti.process_multiple_fields(result['data']['indicatorAdd'])
245247
else:
246-
self.opencti.log('error', '[opencti_indicator] Missing parameters: name and indicator_pattern')
248+
self.opencti.log(
249+
'error',
250+
'[opencti_indicator] Missing parameters: name and indicator_pattern and main_observable_type'
251+
)
247252

248253
"""
249254
Create a Indicator object only if it not exists, update it on request
@@ -256,6 +261,7 @@ def create(self, **kwargs):
256261
name = kwargs.get('name', None)
257262
description = kwargs.get('description', None)
258263
indicator_pattern = kwargs.get('indicator_pattern', None)
264+
main_observable_type = kwargs.get('main_observable_type', None)
259265
pattern_type = kwargs.get('pattern_type', None)
260266
valid_from = kwargs.get('valid_from', None)
261267
valid_until = kwargs.get('valid_until', None)
@@ -287,6 +293,7 @@ def create(self, **kwargs):
287293
name=name,
288294
description=description,
289295
indicator_pattern=indicator_pattern,
296+
main_observable_type=main_observable_type,
290297
pattern_type=pattern_type,
291298
valid_from=valid_from,
292299
valid_until=valid_until,
@@ -297,6 +304,54 @@ def create(self, **kwargs):
297304
createdByRef=created_by_ref
298305
)
299306

307+
"""
308+
Add a Stix-Observable object to Indicator object (observable_refs)
309+
310+
:param id: the id of the Indicator
311+
:param entity_id: the id of the Stix-Observable
312+
:return Boolean
313+
"""
314+
315+
def add_stix_observable(self, **kwargs):
316+
id = kwargs.get('id', None)
317+
indicator = kwargs.get('indicator', None)
318+
stix_observable_id = kwargs.get('stix_observable_id', None)
319+
if id is not None and stix_observable_id is not None:
320+
if indicator is None:
321+
indicator = self.read(id=id)
322+
if indicator is None:
323+
self.opencti.log('error', '[opencti_indicator] Cannot add Object Ref, indicator not found')
324+
return False
325+
if stix_observable_id in indicator['observableRefsIds']:
326+
return True
327+
else:
328+
self.opencti.log(
329+
'info',
330+
'Adding Stix-Observable {' + stix_observable_id + '} to Indicator {' + id + '}'
331+
)
332+
query = """
333+
mutation IndicatorEdit($id: ID!, $input: RelationAddInput) {
334+
indicatorEdit(id: $id) {
335+
relationAdd(input: $input) {
336+
id
337+
}
338+
}
339+
}
340+
"""
341+
self.opencti.query(query, {
342+
'id': id,
343+
'input': {
344+
'fromRole': 'observables_aggregation',
345+
'toId': stix_observable_id,
346+
'toRole': 'soo',
347+
'through': 'observable_refs'
348+
}
349+
})
350+
return True
351+
else:
352+
self.opencti.log('error', '[opencti_indicator] Missing parameters: id and stix_observable_id')
353+
return False
354+
300355
"""
301356
Export an Indicator object in STIX2
302357

pycti/entities/opencti_stix_relation.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -501,8 +501,8 @@ def to_stix2(self, **kwargs):
501501
if self.opencti.not_empty(entity['description']): stix_relation['description'] = entity['description']
502502
stix_relation['source_ref'] = entity['from']['stix_id_key']
503503
stix_relation['target_ref'] = entity['to']['stix_id_key']
504-
stix_relation[CustomProperties.SOURCE_REF] = entity['from']['id']
505-
stix_relation[CustomProperties.TARGET_REF] = entity['to']['id']
504+
stix_relation[CustomProperties.SOURCE_REF] = entity['from']['stix_id_key']
505+
stix_relation[CustomProperties.TARGET_REF] = entity['to']['stix_id_key']
506506
stix_relation['created'] = self.opencti.stix2.format_date(entity['created'])
507507
stix_relation['modified'] = self.opencti.stix2.format_date(entity['modified'])
508508
if self.opencti.not_empty(entity['first_seen']): stix_relation[

pycti/utils/opencti_stix2.py

+26-10
Original file line numberDiff line numberDiff line change
@@ -755,14 +755,14 @@ def export_entity(self, entity_type, entity_id, mode='simple', max_marking_defin
755755
mode=mode,
756756
max_marking_definition_entity=max_marking_definition_entity
757757
)
758-
for object in objects:
759-
object['id'] = object['id'].replace('observable', 'indicator')
760-
if 'source_ref' in object:
761-
object['source_ref'] = object['source_ref'].replace('observable', 'indicator')
762-
if 'target_ref' in object:
763-
object['target_ref'] = object['target_ref'].replace('observable', 'indicator')
764-
bundle['objects'].append(object)
765-
758+
if objects is not None:
759+
for object in objects:
760+
object['id'] = object['id'].replace('observable', 'indicator')
761+
if 'source_ref' in object:
762+
object['source_ref'] = object['source_ref'].replace('observable', 'indicator')
763+
if 'target_ref' in object:
764+
object['target_ref'] = object['target_ref'].replace('observable', 'indicator')
765+
bundle['objects'].append(object)
766766
return bundle
767767

768768
def export_bundle(self, types=[]):
@@ -1280,6 +1280,8 @@ def create_indicator(self, stix_object, update=False):
12801280
name=stix_object['name'],
12811281
description=self.convert_markdown(stix_object['description']) if 'description' in stix_object else '',
12821282
indicator_pattern=stix_object['pattern'],
1283+
main_observable_type=stix_object[
1284+
CustomProperties.OBSERVABLE_TYPE] if CustomProperties.OBSERVABLE_TYPE in stix_object else 'Unknown',
12831285
pattern_type=stix_object[
12841286
CustomProperties.PATTERN_TYPE] if CustomProperties.PATTERN_TYPE in stix_object else 'stix2',
12851287
valid_from=stix_object['valid_from'] if 'valid_from' in stix_object else None,
@@ -1420,11 +1422,25 @@ def import_bundle(self, stix_bundle, update=False, types=None) -> List:
14201422
start_time = time.time()
14211423
for item in stix_bundle['objects']:
14221424
if item['type'] == 'relationship':
1423-
self.import_relationship(item, update, types)
1424-
imported_elements.append({'id': item['id'], 'type': item['type']})
1425+
# Import only relationships between entities
1426+
if 'relationship' not in item[CustomProperties.SOURCE_REF] and \
1427+
'relationship' not in item[CustomProperties.TARGET_REF]:
1428+
self.import_relationship(item, update, types)
1429+
imported_elements.append({'id': item['id'], 'type': item['type']})
14251430
end_time = time.time()
14261431
self.opencti.log('info', "Relationships imported in: %ssecs" % round(end_time - start_time))
14271432

1433+
# StixRelationObjects (with relationships)
1434+
start_time = time.time()
1435+
for item in stix_bundle['objects']:
1436+
if item['type'] == 'relationship':
1437+
if 'relationship' in item[CustomProperties.SOURCE_REF] or \
1438+
'relationship' in item[CustomProperties.TARGET_REF]:
1439+
self.import_relationship(item, update, types)
1440+
imported_elements.append({'id': item['id'], 'type': item['type']})
1441+
end_time = time.time()
1442+
self.opencti.log('info', "Relationships to relationships imported in: %ssecs" % round(end_time - start_time))
1443+
14281444
# StixCyberObservables
14291445
start_time = time.time()
14301446
for item in stix_bundle['objects']:

0 commit comments

Comments
 (0)