Skip to content

Commit 08e374f

Browse files
author
Samuel Hassine
committed
[client] Fix the export of incident
1 parent 5861cdc commit 08e374f

13 files changed

+107
-46
lines changed

examples/add_organization_to_sector.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
# Variables
88
api_url = 'https://demo.opencti.io'
9-
api_token = 'ab3c02bb-2849-4223-be5d-8f61207b4b43'
9+
api_token = 'c2d944bb-aea6-4bd6-b3d7-6c10451e2256'
1010

1111
# OpenCTI initialization
1212
opencti_api_client = OpenCTIApiClient(api_url, api_token)

examples/create_incident_with_ttps_and_observables.py

+48-12
Original file line numberDiff line numberDiff line change
@@ -6,22 +6,26 @@
66
from pycti import OpenCTIApiClient
77

88
# Variables
9-
api_url = 'https://demo.opencti.io'
10-
api_token = 'ab3c02bb-2849-4223-be5d-8f61207b4b43'
9+
api_url = 'http://localhost:4000'
10+
api_token = 'c2d944bb-aea6-4bd6-b3d7-6c10451e2256'
1111

1212
# OpenCTI initialization
1313
opencti_api_client = OpenCTIApiClient(api_url, api_token)
1414

1515
# Define the date
1616
date = parse('2019-12-01').strftime('%Y-%m-%dT%H:%M:%SZ')
1717

18+
# Prepare all the elements of the report
19+
object_refs = []
20+
1821
# Create the incident
1922
incident = opencti_api_client.incident.create(
2023
name="My new incident",
2124
description="We have been compromised",
2225
objective="Espionage"
2326
)
2427
print(incident)
28+
object_refs.append(incident['id'])
2529

2630
# Create the associated report
2731
report = opencti_api_client.report.create(
@@ -32,9 +36,6 @@
3236
)
3337
print(report)
3438

35-
# Prepare all the elements of the report
36-
object_refs = []
37-
3839
# Associate the TTPs to the incident
3940

4041
# Spearphishing Attachment
@@ -43,7 +44,7 @@
4344
ttp1_relation = opencti_api_client.stix_relation.create(
4445
fromType='Incident',
4546
fromId=incident['id'],
46-
toType='Incident',
47+
toType='Attack-Pattern',
4748
toId=ttp1['id'],
4849
relationship_type='uses',
4950
description='We saw the attacker use Spearphishing Attachment.',
@@ -56,11 +57,24 @@
5657
id=ttp1_relation['id'],
5758
kill_chain_phase_id=kill_chain_phase_id
5859
)
59-
# Add observables to the relation
60+
61+
# Create the observable
6062
observable_ttp1 = opencti_api_client.stix_observable.create(
61-
type='Email-Addr',
63+
type='Email-Address',
6264
observable_value='phishing@mail.com'
6365
)
66+
# Indicates the incident itself
67+
observable_ttp1_incident_relation = opencti_api_client.stix_relation.create(
68+
fromType='Stix-Observable',
69+
fromId=observable_ttp1['id'],
70+
toType='Incident',
71+
toId=incident['id'],
72+
relationship_type='indicates',
73+
description='This email address is the sender of the spearphishing in this incident.',
74+
first_seen=date,
75+
last_seen=date
76+
)
77+
# Indicates the relation Incident => uses => TTP
6478
observable_ttp1_relation = opencti_api_client.stix_relation.create(
6579
fromType='Stix-Observable',
6680
fromId=observable_ttp1['id'],
@@ -72,7 +86,12 @@
7286
last_seen=date
7387
)
7488
# Elements for the report
75-
object_refs.extend([ttp1['id'], ttp1_relation['id'], observable_ttp1['id'], observable_ttp1_relation['id']])
89+
object_refs.extend([
90+
ttp1['id'],
91+
ttp1_relation['id'],
92+
observable_ttp1['id'],
93+
observable_ttp1_incident_relation['id']
94+
])
7695

7796
# Registry Run Keys / Startup Folder
7897
ttp2 = opencti_api_client.attack_pattern.read(filters=[{'key': 'external_id', 'values': ['T1060']}])
@@ -81,7 +100,7 @@
81100
ttp2_relation = opencti_api_client.stix_relation.create(
82101
fromType='Incident',
83102
fromId=incident['id'],
84-
toType='Incident',
103+
toType='Attack-Pattern',
85104
toId=ttp2['id'],
86105
relationship_type='uses',
87106
description='We saw the attacker use Registry Run Keys / Startup Folder.',
@@ -99,6 +118,18 @@
99118
type='Registry-Key',
100119
observable_value='Disk security'
101120
)
121+
# Indicates the incident itself
122+
observable_ttp2_incident_relation = opencti_api_client.stix_relation.create(
123+
fromType='Stix-Observable',
124+
fromId=observable_ttp2['id'],
125+
toType='Incident',
126+
toId=incident['id'],
127+
relationship_type='indicates',
128+
description='This registry key is used for persistence of tools in this incident.',
129+
first_seen=date,
130+
last_seen=date
131+
)
132+
# Indicates the relation Incident => uses => TTP
102133
observable_ttp2_relation = opencti_api_client.stix_relation.create(
103134
fromType='Stix-Observable',
104135
fromId=observable_ttp2['id'],
@@ -110,15 +141,20 @@
110141
last_seen=date
111142
)
112143
# Elements for the report
113-
object_refs.extend([ttp2['id'], ttp2_relation['id'], observable_ttp2['id'], observable_ttp2_relation['id']])
144+
object_refs.extend([
145+
ttp2['id'],
146+
ttp2_relation['id'],
147+
observable_ttp2['id'],
148+
observable_ttp2_incident_relation['id']
149+
])
114150

115151
# Data Encrypted
116152
ttp3 = opencti_api_client.attack_pattern.read(filters=[{'key': 'external_id', 'values': ['T1022']}])
117153
print(ttp3)
118154
ttp3_relation = opencti_api_client.stix_relation.create(
119155
fromType='Incident',
120156
fromId=incident['id'],
121-
toType='Incident',
157+
toType='Attack-Pattern',
122158
toId=ttp3['id'],
123159
relationship_type='uses',
124160
description='We saw the attacker use Data Encrypted.',

examples/create_intrusion_set.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
# Variables
77
api_url = 'https://demo.opencti.io'
8-
api_token = 'ab3c02bb-2849-4223-be5d-8f61207b4b43'
8+
api_token = 'c2d944bb-aea6-4bd6-b3d7-6c10451e2256'
99

1010
# OpenCTI initialization
1111
opencti_api_client = OpenCTIApiClient(api_url, api_token)

examples/export_intrusion_set_stix2.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
# Variables
77
api_url = 'https://demo.opencti.io'
8-
api_token = 'ab3c02bb-2849-4223-be5d-8f61207b4b43'
8+
api_token = 'c2d944bb-aea6-4bd6-b3d7-6c10451e2256'
99

1010
# OpenCTI initialization
1111
opencti_api_client = OpenCTIApiClient(api_url, api_token)

examples/export_report_stix2.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,14 @@
44
from pycti import OpenCTIApiClient
55

66
# Variables
7-
api_url = 'https://demo.opencti.io'
8-
api_token = 'ab3c02bb-2849-4223-be5d-8f61207b4b43'
7+
api_url = 'http://localhost:4000'
8+
api_token = 'c2d944bb-aea6-4bd6-b3d7-6c10451e2256'
99

1010
# OpenCTI initialization
1111
opencti_api_client = OpenCTIApiClient(api_url, api_token)
1212

1313
# Get the report
14-
report = opencti_api_client.report.read(id='b52201d6-8da3-4e98-a3f5-e53318d8fb52')
14+
report = opencti_api_client.report.read(id='f465e240-9bfe-41dd-888c-70d7d85143c1')
1515

1616
# Create the bundle
1717
bundle = opencti_api_client.stix2.export_entity('report', report['id'], 'full')

examples/get_attack_pattern_by_mitre_id.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
# Variables
66
api_url = 'https://demo.opencti.io'
7-
api_token = 'ab3c02bb-2849-4223-be5d-8f61207b4b43'
7+
api_token = 'c2d944bb-aea6-4bd6-b3d7-6c10451e2256'
88

99
# OpenCTI initialization
1010
opencti_api_client = OpenCTIApiClient(api_url, api_token)

examples/get_malwares_of_intrusion_set.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
# Variables
66
api_url = 'https://demo.opencti.io'
7-
api_token = 'ab3c02bb-2849-4223-be5d-8f61207b4b43'
7+
api_token = 'c2d944bb-aea6-4bd6-b3d7-6c10451e2256'
88

99
# OpenCTI initialization
1010
opencti_api_client = OpenCTIApiClient(api_url, api_token)

examples/get_marking_definitions.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
# Variables
66
api_url = 'https://demo.opencti.io'
7-
api_token = 'ab3c02bb-2849-4223-be5d-8f61207b4b43'
7+
api_token = 'c2d944bb-aea6-4bd6-b3d7-6c10451e2256'
88

99
# OpenCTI initialization
1010
opencti_api_client = OpenCTIApiClient(api_url, api_token)

examples/get_reports_about_intrusion_set.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
# Variables
66
api_url = 'https://demo.opencti.io'
7-
api_token = 'ab3c02bb-2849-4223-be5d-8f61207b4b43'
7+
api_token = 'c2d944bb-aea6-4bd6-b3d7-6c10451e2256'
88

99
# OpenCTI initialization
1010
opencti_api_client = OpenCTIApiClient(api_url, api_token)

examples/import_stix2_file.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
# Variables
66
api_url = 'https://demo.opencti.io'
7-
api_token = 'ab3c02bb-2849-4223-be5d-8f61207b4b43'
7+
api_token = 'c2d944bb-aea6-4bd6-b3d7-6c10451e2256'
88

99
# OpenCTI initialization
1010
opencti_api_client = OpenCTIApiClient(api_url, api_token)

pycti/api/opencti_api_client.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -2157,10 +2157,9 @@ def resolve_role(self, relation_type, from_type, to_type):
21572157
from_type = 'observable' if (
21582158
(ObservableTypes.has_value(from_type) and (
21592159
relation_type == 'indicates' or relation_type == 'localization' or relation_type == 'gathering')
2160-
) or from_type == 'Stix-Observable'
2160+
) or from_type == 'stix-observable'
21612161
) else from_type
21622162
to_type = to_type.lower()
2163-
21642163
mapping = {
21652164
'uses': {
21662165
'threat-actor': {
@@ -2308,6 +2307,7 @@ def resolve_role(self, relation_type, from_type, to_type):
23082307
'threat-actor': {'from_role': 'indicator', 'to_role': 'characterize'},
23092308
'intrusion-set': {'from_role': 'indicator', 'to_role': 'characterize'},
23102309
'campaign': {'from_role': 'indicator', 'to_role': 'characterize'},
2310+
'incident': {'from_role': 'indicator', 'to_role': 'characterize'},
23112311
'malware': {'from_role': 'indicator', 'to_role': 'characterize'},
23122312
'tool': {'from_role': 'indicator', 'to_role': 'characterize'},
23132313
'stix_relation': {'from_role': 'indicator', 'to_role': 'characterize'},

pycti/utils/opencti_stix2.py

+45-20
Original file line numberDiff line numberDiff line change
@@ -724,7 +724,7 @@ def export_entity(self, entity_type, entity_id, mode='simple', max_marking_defin
724724
'threat-actor': self.opencti.threat_actor.to_stix2,
725725
'intrusion-set': self.opencti.intrusion_set.to_stix2,
726726
'campaign': self.opencti.campaign.to_stix2,
727-
'x-opencti-incident': self.opencti.incident.to_stix2,
727+
'incident': self.opencti.incident.to_stix2,
728728
'malware': self.opencti.malware.to_stix2,
729729
'tool': self.opencti.tool.to_stix2,
730730
'vulnerability': self.opencti.vulnerability.to_stix2,
@@ -736,11 +736,19 @@ def export_entity(self, entity_type, entity_id, mode='simple', max_marking_defin
736736
entity_type,
737737
lambda **kwargs: self.unknown_type({'type': entity_type})
738738
)
739-
bundle['objects'] = do_export(
739+
objects = do_export(
740740
id=entity_id,
741741
mode=mode,
742742
max_marking_definition_entity=max_marking_definition_entity
743743
)
744+
for object in objects:
745+
object['id'] = object['id'].replace('observable', 'indicator')
746+
if 'source_ref' in object:
747+
object['source_ref'] = object['source_ref'].replace('observable', 'indicator')
748+
if 'target_ref' in object:
749+
object['target_ref'] = object['target_ref'].replace('observable', 'indicator')
750+
bundle['objects'].append(object)
751+
744752
return bundle
745753

746754
def export_bundle(self, types=[]):
@@ -972,7 +980,7 @@ def prepare_export(self, entity, stix_object, mode='simple', max_marking_definit
972980
'threat-actor': self.opencti.threat_actor.to_stix2,
973981
'intrusion-set': self.opencti.intrusion_set.to_stix2,
974982
'campaign': self.opencti.campaign.to_stix2,
975-
'x-opencti-incident': self.opencti.incident.to_stix2,
983+
'incident': self.opencti.incident.to_stix2,
976984
'malware': self.opencti.malware.to_stix2,
977985
'tool': self.opencti.tool.to_stix2,
978986
'vulnerability': self.opencti.vulnerability.to_stix2,
@@ -992,13 +1000,12 @@ def prepare_export(self, entity, stix_object, mode='simple', max_marking_definit
9921000
result = result + entity_object_bundle
9931001
for observable_object in observables_to_get:
9941002
observable_object_data = self.export_stix_observable(
995-
self.opencti.process_multiple_fields(
996-
self.opencti.get_stix_observable_by_id(observable_object['id'])
997-
)
1003+
self.opencti.stix_observable.read(id=observable_object['id'])
9981004
)
999-
observable_object_bundle = self.filter_objects(uuids, observable_object_data)
1000-
uuids = uuids + [x['id'] for x in observable_object_bundle]
1001-
result = result + observable_object_bundle
1005+
if observable_object_data is not None:
1006+
observable_object_bundle = self.filter_objects(uuids, observable_object_data)
1007+
uuids = uuids + [x['id'] for x in observable_object_bundle]
1008+
result = result + observable_object_bundle
10021009
for relation_object in relations_to_get:
10031010
relation_object_data = self.opencti.stix_relation.to_stix2(id=relation_object['id'])
10041011
relation_object_bundle = self.filter_objects(uuids, relation_object_data)
@@ -1234,7 +1241,10 @@ def export_stix_observable(self, entity):
12341241
first_seen = relation_first_seen
12351242
stix_observable['valid_from'] = self.format_date(first_seen)
12361243
final_stix_observable = self.prepare_observable(entity, stix_observable)
1237-
return self.prepare_export(entity, final_stix_observable)
1244+
if final_stix_observable is not None:
1245+
return self.prepare_export(entity, final_stix_observable)
1246+
else:
1247+
return None
12381248

12391249
def create_indicator(self, stix_object, update=False):
12401250
indicator_type = None
@@ -1327,16 +1337,31 @@ def prepare_observable(self, entity, stix_observable):
13271337
else:
13281338
observable_type = entity['entity_type']
13291339

1330-
if observable_type == 'file':
1331-
lhs = ObjectPath(observable_type, ['hashes', entity['entity_type'].split('-')[1].upper()])
1332-
ece = ObservationExpression(EqualityComparisonExpression(lhs, HashConstant(entity['observable_value'],
1333-
entity['entity_type'].split('-')[
1334-
1].upper())))
1335-
if observable_type == 'ipv4-addr' or observable_type == 'ipv6-addr' or observable_type == 'domain_name' or observable_type == 'url':
1336-
lhs = ObjectPath(observable_type, ["value"])
1337-
ece = ObservationExpression(EqualityComparisonExpression(lhs, entity['observable_value']))
1338-
stix_observable['pattern'] = str(ece)
1339-
return stix_observable
1340+
try:
1341+
if observable_type == 'file':
1342+
lhs = ObjectPath(observable_type, ['hashes', entity['entity_type'].split('-')[1].upper()])
1343+
ece = ObservationExpression(
1344+
EqualityComparisonExpression(
1345+
lhs,
1346+
HashConstant(
1347+
entity['observable_value'],
1348+
entity['entity_type'].split('-')[1].upper())
1349+
)
1350+
)
1351+
else:
1352+
lhs = ObjectPath(observable_type, ["value"])
1353+
ece = ObservationExpression(
1354+
EqualityComparisonExpression(
1355+
lhs,
1356+
entity['observable_value'])
1357+
)
1358+
except:
1359+
ece = None
1360+
if ece is not None:
1361+
stix_observable['pattern'] = str(ece)
1362+
return stix_observable
1363+
else:
1364+
return None
13401365

13411366
def get_author(self, name):
13421367
if name in self.mapping_cache:

setup.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
print("warning: pypandoc module not found, could not convert Markdown to RST")
1414
read_md = lambda f: open(f, 'r').read()
1515

16-
VERSION = "2.1.0"
16+
VERSION = "2.1.1"
1717

1818

1919
class VerifyVersionCommand(install):

0 commit comments

Comments
 (0)