0
# Relationships and Object Links
1
2
STIX Relationship Objects and utilities for creating and managing connections between STIX objects, including relationships, sightings, and reference resolution across multiple data sources.
3
4
## Capabilities
5
6
### Relationship Objects
7
8
Connect STIX Domain Objects with typed relationships describing how they relate to each other.
9
10
```python { .api }
11
class Relationship:
12
"""
13
Relationship objects describe connections between STIX Domain Objects.
14
15
Required Properties:
16
- relationship_type (str): Type of relationship
17
- source_ref (str): ID of source STIX object
18
- target_ref (str): ID of target STIX object
19
20
Optional Properties:
21
- description (str): Description of the relationship
22
- start_time (timestamp): When relationship started
23
- stop_time (timestamp): When relationship ended
24
"""
25
```
26
27
Usage examples:
28
29
```python
30
from stix2 import Relationship, ThreatActor, Malware, AttackPattern
31
32
# Create objects to relate
33
threat_actor = ThreatActor(
34
name="APT1",
35
threat_actor_types=["nation-state"]
36
)
37
38
malware = Malware(
39
name="Poison Ivy",
40
malware_types=["remote-access-trojan"]
41
)
42
43
attack_pattern = AttackPattern(
44
name="Spear Phishing"
45
)
46
47
# Create relationships
48
uses_malware = Relationship(
49
relationship_type="uses",
50
source_ref=threat_actor.id,
51
target_ref=malware.id,
52
description="APT1 commonly uses Poison Ivy RAT in their operations"
53
)
54
55
uses_technique = Relationship(
56
relationship_type="uses",
57
source_ref=threat_actor.id,
58
target_ref=attack_pattern.id,
59
description="APT1 uses spear phishing for initial access"
60
)
61
62
implements_pattern = Relationship(
63
relationship_type="implements",
64
source_ref=malware.id,
65
target_ref=attack_pattern.id,
66
description="Poison Ivy is delivered via spear phishing attacks"
67
)
68
69
# Time-bounded relationship
70
active_relationship = Relationship(
71
relationship_type="targets",
72
source_ref=threat_actor.id,
73
target_ref="identity--target-organization-uuid",
74
start_time="2020-01-01T00:00:00.000Z",
75
stop_time="2020-12-31T23:59:59.000Z",
76
description="APT1 actively targeted this organization during 2020"
77
)
78
```
79
80
### Common Relationship Types
81
82
STIX defines standard relationship types for connecting different object types:
83
84
```python
85
# Threat Actor relationships
86
actor_uses_malware = Relationship(
87
relationship_type="uses", # ThreatActor -> Malware
88
source_ref=threat_actor.id,
89
target_ref=malware.id
90
)
91
92
actor_targets_identity = Relationship(
93
relationship_type="targets", # ThreatActor -> Identity
94
source_ref=threat_actor.id,
95
target_ref=identity.id
96
)
97
98
actor_attributed_to = Relationship(
99
relationship_type="attributed-to", # ThreatActor -> Identity
100
source_ref=threat_actor.id,
101
target_ref=sponsor_identity.id
102
)
103
104
actor_impersonates = Relationship(
105
relationship_type="impersonates", # ThreatActor -> Identity
106
source_ref=threat_actor.id,
107
target_ref=impersonated_identity.id
108
)
109
110
# Malware relationships
111
malware_targets_identity = Relationship(
112
relationship_type="targets", # Malware -> Identity
113
source_ref=malware.id,
114
target_ref=victim_identity.id
115
)
116
117
malware_uses_tool = Relationship(
118
relationship_type="uses", # Malware -> Tool
119
source_ref=malware.id,
120
target_ref=tool.id
121
)
122
123
malware_variant_of = Relationship(
124
relationship_type="variant-of", # Malware -> Malware
125
source_ref=malware_variant.id,
126
target_ref=malware_family.id
127
)
128
129
# Indicator relationships
130
indicator_indicates = Relationship(
131
relationship_type="indicates", # Indicator -> ThreatActor/Malware/AttackPattern
132
source_ref=indicator.id,
133
target_ref=malware.id
134
)
135
136
# Campaign relationships
137
campaign_uses_malware = Relationship(
138
relationship_type="uses", # Campaign -> Malware
139
source_ref=campaign.id,
140
target_ref=malware.id
141
)
142
143
campaign_attributed_to = Relationship(
144
relationship_type="attributed-to", # Campaign -> ThreatActor
145
source_ref=campaign.id,
146
target_ref=threat_actor.id
147
)
148
149
# Attack Pattern relationships
150
pattern_mitigated_by = Relationship(
151
relationship_type="mitigated-by", # AttackPattern -> CourseOfAction
152
source_ref=attack_pattern.id,
153
target_ref=course_of_action.id
154
)
155
156
# Course of Action relationships
157
coa_mitigates = Relationship(
158
relationship_type="mitigates", # CourseOfAction -> AttackPattern/Malware
159
source_ref=course_of_action.id,
160
target_ref=attack_pattern.id
161
)
162
163
# Vulnerability relationships
164
vuln_targets = Relationship(
165
relationship_type="targets", # Vulnerability -> Identity/Software
166
source_ref=vulnerability.id,
167
target_ref=software.id
168
)
169
170
# Tool relationships
171
tool_targets = Relationship(
172
relationship_type="targets", # Tool -> Identity/Infrastructure
173
source_ref=tool.id,
174
target_ref=infrastructure.id
175
)
176
177
# Infrastructure relationships
178
infra_communicates_with = Relationship(
179
relationship_type="communicates-with", # Infrastructure -> Infrastructure
180
source_ref=infrastructure1.id,
181
target_ref=infrastructure2.id
182
)
183
184
infra_consists_of = Relationship(
185
relationship_type="consists-of", # Infrastructure -> Infrastructure/Software
186
source_ref=infrastructure.id,
187
target_ref=component.id
188
)
189
190
infra_controls = Relationship(
191
relationship_type="controls", # Infrastructure -> Infrastructure/Malware
192
source_ref=c2_server.id,
193
target_ref=malware.id
194
)
195
196
infra_delivers = Relationship(
197
relationship_type="delivers", # Infrastructure -> Malware
198
source_ref=infrastructure.id,
199
target_ref=malware.id
200
)
201
202
infra_hosts = Relationship(
203
relationship_type="hosts", # Infrastructure -> Tool/Malware
204
source_ref=infrastructure.id,
205
target_ref=malware.id
206
)
207
208
infra_owns = Relationship(
209
relationship_type="owns", # Infrastructure -> Infrastructure
210
source_ref=infrastructure.id,
211
target_ref=owned_infrastructure.id
212
)
213
214
# Report relationships
215
report_object_refs = [ # Report -> any SDO/SRO (via object_refs property)
216
threat_actor.id,
217
malware.id,
218
indicator.id,
219
uses_malware.id
220
]
221
222
report = Report(
223
name="APT1 Analysis Report",
224
published="2021-04-23T10:30:00.000Z",
225
object_refs=report_object_refs
226
)
227
```
228
229
### Sighting Objects
230
231
Represent observations or encounters with STIX objects in the real world.
232
233
```python { .api }
234
class Sighting:
235
"""
236
Sighting objects represent observations of STIX objects.
237
238
Required Properties:
239
- sighting_of_ref (str): ID of sighted STIX object
240
241
Optional Properties:
242
- count (int): Number of times sighted
243
- first_seen (timestamp): First sighting time
244
- last_seen (timestamp): Last sighting time
245
- where_sighted_refs (list): References to identities that sighted
246
- observed_data_refs (list): References to observed data
247
- summary (bool): Whether this is a summary sighting
248
- description (str): Description of the sighting
249
"""
250
```
251
252
Usage examples:
253
254
```python
255
from stix2 import Sighting, Indicator, Identity
256
257
# Create indicator and observer identity
258
indicator = Indicator(
259
name="Malicious Domain",
260
indicator_types=["malicious-activity"],
261
pattern_type="stix",
262
pattern="[domain-name:value = 'evil.com']"
263
)
264
265
security_org = Identity(
266
name="ACME Security Team",
267
identity_class="organization"
268
)
269
270
# Create sighting of indicator
271
sighting = Sighting(
272
sighting_of_ref=indicator.id,
273
count=5,
274
first_seen="2021-04-23T10:30:00.000Z",
275
last_seen="2021-04-23T11:45:00.000Z",
276
where_sighted_refs=[security_org.id],
277
description="Domain observed in network traffic attempting C2 communication"
278
)
279
280
# Sighting with observed data
281
from stix2 import ObservedData
282
283
observed_data = ObservedData(
284
first_observed="2021-04-23T10:30:00.000Z",
285
last_observed="2021-04-23T10:30:00.000Z",
286
number_observed=1,
287
objects={
288
"0": {
289
"type": "domain-name",
290
"value": "evil.com"
291
}
292
}
293
)
294
295
detailed_sighting = Sighting(
296
sighting_of_ref=indicator.id,
297
count=1,
298
first_seen="2021-04-23T10:30:00.000Z",
299
where_sighted_refs=[security_org.id],
300
observed_data_refs=[observed_data.id],
301
description="Domain observed in DNS logs"
302
)
303
304
# Summary sighting (aggregated data)
305
summary_sighting = Sighting(
306
sighting_of_ref=indicator.id,
307
count=127,
308
first_seen="2021-04-01T00:00:00.000Z",
309
last_seen="2021-04-30T23:59:59.000Z",
310
where_sighted_refs=[security_org.id],
311
summary=True,
312
description="Monthly summary: domain seen 127 times across network"
313
)
314
```
315
316
### Reference Resolution
317
318
Utilities for resolving object references across data sources.
319
320
```python
321
from stix2 import MemoryStore, CompositeDataSource
322
323
# Store related objects
324
store = MemoryStore([
325
threat_actor,
326
malware,
327
uses_malware,
328
indicator,
329
sighting
330
])
331
332
# Resolve relationship targets
333
relationship = store.get(uses_malware.id)
334
source_object = store.get(relationship.source_ref) # ThreatActor
335
target_object = store.get(relationship.target_ref) # Malware
336
337
print(f"{source_object.name} uses {target_object.name}")
338
339
# Find all relationships involving an object
340
threat_actor_relationships = store.query([
341
Filter('type', '=', 'relationship'),
342
Filter('source_ref', '=', threat_actor.id)
343
])
344
345
# Find sightings of an indicator
346
indicator_sightings = store.query([
347
Filter('type', '=', 'sighting'),
348
Filter('sighting_of_ref', '=', indicator.id)
349
])
350
351
# Composite data source for cross-store resolution
352
composite = CompositeDataSource([
353
memory_store,
354
filesystem_store,
355
taxii_store
356
])
357
358
# Resolve references across multiple stores
359
resolved_relationship = composite.get(relationship_id)
360
resolved_source = composite.get(resolved_relationship.source_ref)
361
```
362
363
### Relationship Patterns
364
365
Common patterns for modeling threat intelligence relationships:
366
367
```python
368
# Attribution chain: Campaign -> ThreatActor -> Identity
369
campaign_attribution = Relationship(
370
relationship_type="attributed-to",
371
source_ref=campaign.id,
372
target_ref=threat_actor.id
373
)
374
375
actor_attribution = Relationship(
376
relationship_type="attributed-to",
377
source_ref=threat_actor.id,
378
target_ref=nation_state_identity.id
379
)
380
381
# Attack chain: ThreatActor -> AttackPattern -> Vulnerability -> Software
382
actor_uses_pattern = Relationship(
383
relationship_type="uses",
384
source_ref=threat_actor.id,
385
target_ref=attack_pattern.id
386
)
387
388
pattern_targets_vuln = Relationship(
389
relationship_type="targets",
390
source_ref=attack_pattern.id,
391
target_ref=vulnerability.id
392
)
393
394
vuln_in_software = Relationship(
395
relationship_type="targets",
396
source_ref=vulnerability.id,
397
target_ref=software.id
398
)
399
400
# Infrastructure relationships: C2 -> Malware <- ThreatActor
401
c2_hosts_malware = Relationship(
402
relationship_type="hosts",
403
source_ref=c2_infrastructure.id,
404
target_ref=malware.id
405
)
406
407
actor_uses_c2 = Relationship(
408
relationship_type="uses",
409
source_ref=threat_actor.id,
410
target_ref=c2_infrastructure.id
411
)
412
413
# Mitigation relationships: CourseOfAction -> AttackPattern/Malware
414
mitigation_blocks_pattern = Relationship(
415
relationship_type="mitigates",
416
source_ref=course_of_action.id,
417
target_ref=attack_pattern.id
418
)
419
420
# Indicator relationships: Indicator -> ThreatActor/Malware/Campaign
421
indicator_indicates_actor = Relationship(
422
relationship_type="indicates",
423
source_ref=indicator.id,
424
target_ref=threat_actor.id
425
)
426
427
# Version relationships: Malware -> Malware (variant-of)
428
new_version_relationship = Relationship(
429
relationship_type="variant-of",
430
source_ref=malware_v2.id,
431
target_ref=malware_v1.id,
432
description="Version 2 of the malware family"
433
)
434
```
435
436
### Querying Relationships
437
438
Find and analyze relationships between objects:
439
440
```python
441
# Find all objects a threat actor uses
442
threat_actor_uses = store.query([
443
Filter('type', '=', 'relationship'),
444
Filter('relationship_type', '=', 'uses'),
445
Filter('source_ref', '=', threat_actor.id)
446
])
447
448
for rel in threat_actor_uses:
449
target = store.get(rel.target_ref)
450
print(f"ThreatActor uses {target.type}: {target.name}")
451
452
# Find all indicators that indicate a specific malware
453
malware_indicators = store.query([
454
Filter('type', '=', 'relationship'),
455
Filter('relationship_type', '=', 'indicates'),
456
Filter('target_ref', '=', malware.id)
457
])
458
459
for rel in malware_indicators:
460
indicator = store.get(rel.source_ref)
461
print(f"Indicator: {indicator.name}")
462
463
# Find all sightings by a specific organization
464
org_sightings = store.query([
465
Filter('type', '=', 'sighting'),
466
Filter('where_sighted_refs', 'contains', security_org.id)
467
])
468
469
# Complex relationship queries
470
# Find all malware used by threat actors targeting a specific sector
471
financial_targets = store.query([
472
Filter('type', '=', 'identity'),
473
Filter('sectors', 'contains', 'financial-services')
474
])
475
476
for target in financial_targets:
477
# Find threat actors targeting this identity
478
targeting_rels = store.query([
479
Filter('type', '=', 'relationship'),
480
Filter('relationship_type', '=', 'targets'),
481
Filter('target_ref', '=', target.id)
482
])
483
484
for targeting_rel in targeting_rels:
485
actor = store.get(targeting_rel.source_ref)
486
if actor and actor.type == 'threat-actor':
487
# Find malware used by this actor
488
malware_rels = store.query([
489
Filter('type', '=', 'relationship'),
490
Filter('relationship_type', '=', 'uses'),
491
Filter('source_ref', '=', actor.id)
492
])
493
494
for malware_rel in malware_rels:
495
malware = store.get(malware_rel.target_ref)
496
if malware and malware.type == 'malware':
497
print(f"{actor.name} uses {malware.name} against {target.name}")
498
```