One of the relationships supported by the STIX data model is the relationship between campaigns and indicators. It allows for indicators to be directly linked to any campaigns of activity that the indicator is considered to be a member of. This allows network defenders to better understand the pattern of behavior behind detected attacks and link it to other related data (victim targeting, previous incidents, attributed threat actors, etc.)
Prior to STIX 1.1, the Campaign structure contained relationships to Indicators. In STIX 1.1, the directionality of this relationship was changed so that Indicators could now contain relationships to Campaigns; furthermore the “old” style Campaign to Indicator relationship construct was deprecated. Because this was done in a minor release, however, the “old” style still exists in the data model even though it has been deprecated. Support for the “old” style will be removed in the next major release of STIX.
The old-style approach, which was used in pre-1.1 versions of STIX, captures the Indicator<=>Campaign relationship on the Campaign construct. The list of indicators that might indicate the campaign are included either as references or directly embedded within the campaign.
During the 1.1 release the community determined that this approach had several major weaknesses:
Because this was done as a minor release, however, the previous capability remains in the schema. Its use is permitted but discouraged by the specification.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<stix:Indicators>
<stix:Indicator id="example:indicator-c43a0a05-e8d2-4f64-ae37-3f3fb153f8d9" timestamp="2014-09-09T19:58:39.608000+00:00" xsi:type='indicator:IndicatorType' negate="false" version="2.1.1">
<indicator:Title>IP Address for known C2 Channel</indicator:Title>
<indicator:Type xsi:type="stixVocabs:IndicatorTypeVocab-1.1">IP Watchlist</indicator:Type>
<indicator:Observable id="example:Observable-f1712715-9bcd-404a-bf47-76504cf1232c">
<cybox:Object id="example:Address-c4d21d91-2bea-4b19-ac53-c513f1b1bc51">
<cybox:Properties xsi:type="AddressObj:AddressObjectType" category="ipv4-addr">
<AddressObj:Address_Value condition="Equals">10.0.0.0</AddressObj:Address_Value>
</cybox:Properties>
</cybox:Object>
</indicator:Observable>
</stix:Indicator>
</stix:Indicators>
<stix:Campaigns>
<stix:Campaign id="example:Campaign-b549a58c-afd9-4847-85c3-5be13d56d3cc" timestamp="2014-09-09T19:58:39.609000+00:00" xsi:type='campaign:CampaignType' version="1.2">
<campaign:Title>Operation Omega</campaign:Title>
<campaign:Related_Indicators>
<campaign:Related_Indicator>
<stixCommon:Indicator idref="example:indicator-c43a0a05-e8d2-4f64-ae37-3f3fb153f8d9" xsi:type='indicator:IndicatorType' negate="false" version="2.1.1"/>
</campaign:Related_Indicator>
</campaign:Related_Indicators>
</stix:Campaign>
</stix:Campaigns>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
package = STIXPackage()
# Create the indicator
indicator = Indicator(title="IP Address for known C2 Channel")
indicator.add_indicator_type("IP Watchlist")
address = Address(category="ipv4-addr")
address.address_value = "10.0.0.0"
address.address_value.condition = "Equals"
indicator.observable = address
package.add_indicator(indicator)
# Create the campaign
campaign = Campaign(title="Operation Omega")
package.add_campaign(campaign)
# Link the campaign to the indicator
campaign.related_indicators.append(RelatedIndicator(item=Indicator(idref=indicator.id_)))
1
2
3
4
5
6
7
8
9
10
11
# Collect indicators by ID
indicators = {}
for indicator in pkg.indicators:
indicators[indicator.id_] = indicator
# Walk all campaigns
for campaign in pkg.campaigns:
print("Campaign: " + campaign.title)
# And list relationships to indicators
for indicator in campaign.related_indicators:
print(" - Related To: " + indicators[indicator.item.idref].title)
The new structure is similar to the old one, with two exceptions:
This new approach is encouraged for all versions of STIX in which it is valid (1.1 and beyond).
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<stix:Indicators>
<stix:Indicator id="example:indicator-c43a0a05-e8d2-4f64-ae37-3f3fb153f8d9" timestamp="2014-09-09T19:58:39.608000+00:00" xsi:type='indicator:IndicatorType' negate="false" version="2.1.1">
<indicator:Title>IP Address for known C2 Channel</indicator:Title>
<indicator:Type xsi:type="stixVocabs:IndicatorTypeVocab-1.1">IP Watchlist</indicator:Type>
<indicator:Observable id="example:Observable-f1712715-9bcd-404a-bf47-76504cf1232c">
<cybox:Object id="example:Address-c4d21d91-2bea-4b19-ac53-c513f1b1bc51">
<cybox:Properties xsi:type="AddressObj:AddressObjectType" category="ipv4-addr">
<AddressObj:Address_Value condition="Equals">10.0.0.0</AddressObj:Address_Value>
</cybox:Properties>
</cybox:Object>
</indicator:Observable>
<indicator:Related_Campaigns>
<indicator:Related_Campaign>
<stixCommon:Campaign idref="example:Campaign-b549a58c-afd9-4847-85c3-5be13d56d3cc" timestamp="2014-09-09T19:58:39.609000+00:00" />
</indicator:Related_Campaign>
</indicator:Related_Campaigns>
</stix:Indicator>
</stix:Indicators>
<stix:Campaigns>
<stix:Campaign id="example:Campaign-b549a58c-afd9-4847-85c3-5be13d56d3cc" timestamp="2014-09-09T19:58:39.609000+00:00" xsi:type='campaign:CampaignType' version="1.2">
<campaign:Title>Operation Omega</campaign:Title>
</stix:Campaign>
</stix:Campaigns>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package = STIXPackage()
# Create the indicator
indicator = Indicator(title="IP Address for known C2 Channel")
indicator.add_indicator_type("IP Watchlist")
address = Address(category="ipv4-addr")
address.address_value = "10.0.0.0"
address.address_value.condition = "Equals"
indicator.observable = address
package.add_indicator(indicator)
# Create the campaign
campaign = Campaign(title="Operation Omega")
package.add_campaign(campaign)
# Link the indicator to the campaign
# TODO: Broken, see #192
# indicator.related_campaigns.append(RelatedCampaign(item=Campaign(idref=campaign.id_)))
1
2
3
4
5
6
7
8
9
10
11
12
# Collect campaigns by ID
campaigns = {}
for campaign in pkg.campaigns:
campaigns[campaign.id_] = campaign
# Walk all campaigns
for indicator in pkg.indicators:
print("Indicator: " + indicator.title)
# And list relationships to campaigns
# Broken, see #192
# for campaign in indicator.related_campaigns:
# print(" - Related To: " + campaigns[campaign.item.idref].title)
No, unless the profile you’re conforming to requires it or you’ve heard from consumers that you interface with that they need it. In particular, you should not duplicate data using both approaches: if you use the new approach, do not use the old approach and vice-versa.
Producers who already support the old approach are still considered compliant with the specification.
Maybe, if allowed by your profile or if any of your producers are creating it. It’s possible that you will need to support both: the new approach for those that support it and the old approach for those that do not. When doing this, it can be tempting to convert the old-style relationships to the new style.
If you own and control the content then it can safely be convered to the new format. The following steps roughly indicate how to do so, though the specifics may vary depending on your data store and whether you have consumers to notify.
Be very careful when converting content that you do not control to the new style. Updates to that content by the producer could interfere with your changes and, if at some point the producer does convert, you may end up in an inconsistent state with what they’re producing.