Produce and consume STIX 2 JSON content for cyber threat intelligence
Comprehensive pattern expression system for STIX indicator patterns including observation expressions, boolean logic, comparison operations, and temporal qualifiers for complex threat detection rules.
Core classes for building STIX pattern expressions programmatically.
class ObservationExpression:
"""
Base class for STIX observation expressions in patterns.
Constructor Parameters:
- operand: The operand expression (comparison, boolean, etc.)
"""
class AndObservationExpression:
"""
AND operation between two observation expressions.
Constructor Parameters:
- operands (list): List of observation expressions to AND together
"""
class OrObservationExpression:
"""
OR operation between two observation expressions.
Constructor Parameters:
- operands (list): List of observation expressions to OR together
"""
class FollowedByObservationExpression:
"""
Temporal FOLLOWEDBY operation between observation expressions.
Constructor Parameters:
- operands (list): List of observation expressions in temporal order
"""
class QualifiedObservationExpression:
"""
Observation expression with temporal qualifiers.
Constructor Parameters:
- observation_expression: Base observation expression
- qualifier: Temporal qualifier (WITHIN, REPEATS, etc.)
"""
class ParentheticalExpression:
"""
Parenthetical grouping of expressions.
Constructor Parameters:
- expression: Expression to wrap in parentheses
"""Boolean logic operations for combining pattern conditions.
class AndBooleanExpression:
"""
Boolean AND operation between expressions.
Constructor Parameters:
- operands (list): List of expressions to AND together
"""
class OrBooleanExpression:
"""
Boolean OR operation between expressions.
Constructor Parameters:
- operands (list): List of expressions to OR together
"""Usage examples:
from stix2 import (
ObjectPath, EqualityComparisonExpression, StringConstant,
AndBooleanExpression, OrBooleanExpression, ObservationExpression
)
# Create basic comparison expressions
ip_comparison = EqualityComparisonExpression(
ObjectPath("ipv4-addr", ["value"]),
StringConstant("192.168.1.100")
)
port_comparison = EqualityComparisonExpression(
ObjectPath("network-traffic", ["dst_port"]),
IntegerConstant(80)
)
# Combine with boolean AND
and_expression = AndBooleanExpression([ip_comparison, port_comparison])
# Create observation expression
observation = ObservationExpression(and_expression)
# Pattern string would be: "[ipv4-addr:value = '192.168.1.100' AND network-traffic:dst_port = 80]"
# Boolean OR example
protocol_http = EqualityComparisonExpression(
ObjectPath("network-traffic", ["protocols", 0]),
StringConstant("http")
)
protocol_https = EqualityComparisonExpression(
ObjectPath("network-traffic", ["protocols", 0]),
StringConstant("https")
)
or_expression = OrBooleanExpression([protocol_http, protocol_https])Various comparison operations for pattern matching.
class EqualityComparisonExpression:
"""
Equality comparison (=) between object path and constant.
Constructor Parameters:
- lhs: Left-hand side (typically ObjectPath)
- rhs: Right-hand side (typically constant value)
"""
class GreaterThanComparisonExpression:
"""Greater than comparison (>) between object path and constant."""
class GreaterThanEqualComparisonExpression:
"""Greater than or equal comparison (>=) between object path and constant."""
class LessThanComparisonExpression:
"""Less than comparison (<) between object path and constant."""
class LessThanEqualComparisonExpression:
"""Less than or equal comparison (<=) between object path and constant."""
class InComparisonExpression:
"""IN comparison for checking membership in a set."""
class LikeComparisonExpression:
"""LIKE comparison for pattern matching with wildcards."""
class MatchesComparisonExpression:
"""MATCHES comparison for regular expression matching."""
class IsSubsetComparisonExpression:
"""ISSUBSET comparison for subset relationships."""
class IsSupersetComparisonExpression:
"""ISSUPERSET comparison for superset relationships."""Usage examples:
from stix2 import (
ObjectPath, EqualityComparisonExpression, GreaterThanComparisonExpression,
LikeComparisonExpression, MatchesComparisonExpression, InComparisonExpression,
StringConstant, IntegerConstant, ListConstant
)
# Equality comparison
file_hash_eq = EqualityComparisonExpression(
ObjectPath("file", ["hashes", "MD5"]),
StringConstant("d41d8cd98f00b204e9800998ecf8427e")
)
# Numeric comparisons
file_size_gt = GreaterThanComparisonExpression(
ObjectPath("file", ["size"]),
IntegerConstant(1000000) # Files larger than 1MB
)
# Pattern matching with LIKE (SQL-style wildcards)
domain_like = LikeComparisonExpression(
ObjectPath("domain-name", ["value"]),
StringConstant("*.evil.com") # Subdomains of evil.com
)
# Regular expression matching
email_regex = MatchesComparisonExpression(
ObjectPath("email-addr", ["value"]),
StringConstant(r"^[a-zA-Z0-9._%+-]+@evil\.com$")
)
# IN comparison for membership
suspicious_ports = InComparisonExpression(
ObjectPath("network-traffic", ["dst_port"]),
ListConstant([1337, 31337, 4444, 5555]) # Common backdoor ports
)Specify paths to properties within STIX Cyber Observable Objects.
class ObjectPath:
"""
Path to a property within a STIX Cyber Observable Object.
Constructor Parameters:
- object_type_name (str): Type of STIX object (e.g., "file", "ipv4-addr")
- property_path (list): List of property names/indices forming the path
"""
class BasicObjectPathComponent:
"""
Basic property name component of an object path.
Constructor Parameters:
- property_name (str): Name of the property
"""
class ListObjectPathComponent:
"""
List index component of an object path.
Constructor Parameters:
- index (int): List index (0-based)
"""
class ReferenceObjectPathComponent:
"""
Object reference component of an object path.
Constructor Parameters:
- reference_property (str): Name of reference property
"""Usage examples:
from stix2 import ObjectPath
# Simple property paths
ip_address = ObjectPath("ipv4-addr", ["value"])
file_name = ObjectPath("file", ["name"])
email_subject = ObjectPath("email-message", ["subject"])
# Nested property paths
file_hash_md5 = ObjectPath("file", ["hashes", "MD5"])
file_hash_sha256 = ObjectPath("file", ["hashes", "SHA-256"])
# Array/list index paths
first_protocol = ObjectPath("network-traffic", ["protocols", 0])
second_protocol = ObjectPath("network-traffic", ["protocols", 1])
# Extension property paths
http_method = ObjectPath("network-traffic", ["extensions", "http-request-ext", "request_method"])
pe_file_type = ObjectPath("file", ["extensions", "windows-pebinary-ext", "pe_type"])
# Complex nested paths
ntfs_ads_name = ObjectPath("file", ["extensions", "ntfs-ext", "alternate_data_streams", 0, "name"])
registry_value = ObjectPath("windows-registry-key", ["values", 0, "data"])
# Object reference paths (following references)
parent_dir = ObjectPath("file", ["parent_directory_ref"])
creator_user = ObjectPath("process", ["creator_user_ref"])
# Patterns using these paths
patterns = [
f"[{ip_address} = '192.168.1.1']",
f"[{file_hash_md5} = 'abc123def456']",
f"[{first_protocol} = 'tcp']",
f"[{http_method} = 'POST']"
]Various types of constant values used in pattern expressions.
class StringConstant:
"""String constant value."""
def __init__(self, value): ...
class IntegerConstant:
"""Integer constant value."""
def __init__(self, value): ...
class FloatConstant:
"""Float constant value."""
def __init__(self, value): ...
class BooleanConstant:
"""Boolean constant value."""
def __init__(self, value): ...
class BinaryConstant:
"""Binary data constant value."""
def __init__(self, value): ...
class HashConstant:
"""Hash value constant."""
def __init__(self, value): ...
class HexConstant:
"""Hexadecimal constant value."""
def __init__(self, value): ...
class TimestampConstant:
"""Timestamp constant value."""
def __init__(self, value): ...
class ListConstant:
"""List of constant values."""
def __init__(self, value): ...Usage examples:
from stix2 import (
StringConstant, IntegerConstant, FloatConstant, BooleanConstant,
HashConstant, HexConstant, TimestampConstant, ListConstant, BinaryConstant
)
# String constants
domain_str = StringConstant("malicious.com")
user_agent = StringConstant("Malicious-Bot/1.0")
# Numeric constants
file_size = IntegerConstant(1048576) # 1MB
confidence_score = FloatConstant(0.85)
# Boolean constants
is_encrypted = BooleanConstant(True)
is_signed = BooleanConstant(False)
# Hash constants
md5_hash = HashConstant("d41d8cd98f00b204e9800998ecf8427e")
sha256_hash = HashConstant("e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855")
# Hex constants
magic_bytes = HexConstant("4D5A") # PE file magic bytes
byte_pattern = HexConstant("DEADBEEF")
# Timestamp constants
start_time = TimestampConstant("2021-04-23T10:30:00.000Z")
end_time = TimestampConstant("2021-04-23T11:00:00.000Z")
# List constants
port_list = ListConstant([80, 443, 8080, 8443])
protocol_list = ListConstant(["tcp", "http"])
hash_list = ListConstant([
"abc123def456",
"def456ghi789",
"ghi789jkl012"
])
# Binary constants
binary_data = BinaryConstant(b"\\x4D\\x5A\\x90\\x00") # PE header bytesAdd temporal constraints to observation expressions.
class WithinQualifier:
"""
WITHIN qualifier for time-bounded observations.
Constructor Parameters:
- time_interval (int): Time interval in seconds
"""
class RepeatQualifier:
"""
REPEATS qualifier for repeated observations.
Constructor Parameters:
- times (int): Number of repetitions required
"""
class StartStopQualifier:
"""
START/STOP qualifier for time-bounded observations.
Constructor Parameters:
- start_time (timestamp): Start time for observations
- stop_time (timestamp): Stop time for observations
"""Usage examples:
from stix2 import (
WithinQualifier, RepeatQualifier, StartStopQualifier,
QualifiedObservationExpression, ObservationExpression
)
# Create base observation
base_observation = ObservationExpression(
EqualityComparisonExpression(
ObjectPath("ipv4-addr", ["value"]),
StringConstant("192.168.1.100")
)
)
# WITHIN qualifier - observe within 300 seconds (5 minutes)
within_qualifier = WithinQualifier(300)
within_observation = QualifiedObservationExpression(
base_observation,
within_qualifier
)
# Pattern: "[ipv4-addr:value = '192.168.1.100'] WITHIN 300 SECONDS"
# REPEATS qualifier - must be observed 3 times
repeat_qualifier = RepeatQualifier(3)
repeat_observation = QualifiedObservationExpression(
base_observation,
repeat_qualifier
)
# Pattern: "[ipv4-addr:value = '192.168.1.100'] REPEATS 3 TIMES"
# START/STOP qualifier - observe within specific time window
start_stop_qualifier = StartStopQualifier(
TimestampConstant("2021-04-23T10:00:00.000Z"),
TimestampConstant("2021-04-23T18:00:00.000Z")
)
bounded_observation = QualifiedObservationExpression(
base_observation,
start_stop_qualifier
)
# Pattern: "[ipv4-addr:value = '192.168.1.100'] START t'2021-04-23T10:00:00.000Z' STOP t'2021-04-23T18:00:00.000Z'"
# Combining qualifiers with complex observations
complex_observation = QualifiedObservationExpression(
AndObservationExpression([
ObservationExpression(EqualityComparisonExpression(
ObjectPath("network-traffic", ["dst_ref.value"]),
StringConstant("192.168.1.100")
)),
ObservationExpression(EqualityComparisonExpression(
ObjectPath("network-traffic", ["dst_port"]),
IntegerConstant(4444)
))
]),
RepeatQualifier(5)
)
# Pattern: "[network-traffic:dst_ref.value = '192.168.1.100' AND network-traffic:dst_port = 4444] REPEATS 5 TIMES"Build sophisticated detection patterns using combinations of expressions.
from stix2 import Indicator
# File-based indicator with multiple conditions
file_pattern = AndBooleanExpression([
EqualityComparisonExpression(
ObjectPath("file", ["hashes", "MD5"]),
StringConstant("d41d8cd98f00b204e9800998ecf8427e")
),
EqualityComparisonExpression(
ObjectPath("file", ["name"]),
StringConstant("malware.exe")
),
GreaterThanComparisonExpression(
ObjectPath("file", ["size"]),
IntegerConstant(50000)
)
])
file_indicator = Indicator(
name="Malicious PE File",
indicator_types=["malicious-activity"],
pattern_type="stix",
pattern=f"[{file_pattern}]"
)
# Network-based indicator with temporal constraints
network_base = AndBooleanExpression([
InComparisonExpression(
ObjectPath("network-traffic", ["dst_ref.value"]),
ListConstant(["192.168.1.100", "10.0.0.1", "172.16.0.1"])
),
InComparisonExpression(
ObjectPath("network-traffic", ["dst_port"]),
ListConstant([4444, 5555, 6666])
),
EqualityComparisonExpression(
ObjectPath("network-traffic", ["protocols", 0]),
StringConstant("tcp")
)
])
network_observation = QualifiedObservationExpression(
ObservationExpression(network_base),
WithinQualifier(3600) # Within 1 hour
)
network_indicator = Indicator(
name="C2 Communication Pattern",
indicator_types=["malicious-activity"],
pattern_type="stix",
pattern=f"{network_observation}"
)
# Multi-observable pattern with FOLLOWEDBY
initial_access = ObservationExpression(
EqualityComparisonExpression(
ObjectPath("email-message", ["subject"]),
StringConstant("Urgent: Account Verification Required")
)
)
payload_download = ObservationExpression(
LikeComparisonExpression(
ObjectPath("url", ["value"]),
StringConstant("http://malicious.com/*")
)
)
file_execution = ObservationExpression(
AndBooleanExpression([
LikeComparisonExpression(
ObjectPath("process", ["name"]),
StringConstant("*.exe")
),
EqualityComparisonExpression(
ObjectPath("process", ["parent_ref.name"]),
StringConstant("outlook.exe")
)
])
)
attack_chain = FollowedByObservationExpression([
initial_access,
payload_download,
file_execution
])
chain_indicator = Indicator(
name="Email-Based Attack Chain",
indicator_types=["malicious-activity"],
pattern_type="stix",
pattern=f"{attack_chain}"
)
# Advanced pattern with multiple qualifiers
advanced_pattern = QualifiedObservationExpression(
OrObservationExpression([
QualifiedObservationExpression(
ObservationExpression(
EqualityComparisonExpression(
ObjectPath("process", ["name"]),
StringConstant("cmd.exe")
)
),
RepeatQualifier(3)
),
QualifiedObservationExpression(
ObservationExpression(
EqualityComparisonExpression(
ObjectPath("process", ["name"]),
StringConstant("powershell.exe")
)
),
RepeatQualifier(2)
)
]),
WithinQualifier(600) # Within 10 minutes
)
advanced_indicator = Indicator(
name="Suspicious Process Activity",
indicator_types=["malicious-activity"],
pattern_type="stix",
pattern=f"{advanced_pattern}"
)Validate pattern syntax and test against observed data.
from stix2 import parse_observable
def validate_pattern_against_data(pattern_str, observed_objects):
"""
Validate a STIX pattern against observed data.
Note: This is a simplified example - real pattern matching
would require a full STIX pattern engine.
"""
# Parse observed data
observables = []
for obj_data in observed_objects:
try:
observable = parse_observable(obj_data)
observables.append(observable)
except Exception as e:
print(f"Error parsing observable: {e}")
continue
# Simple pattern validation (would need full parser in reality)
print(f"Pattern: {pattern_str}")
print(f"Observables to test: {len(observables)}")
# Example: check if pattern references match observable types
for observable in observables:
print(f"Observable type: {observable.type}")
if observable.type in pattern_str:
print(f" - Pattern may match {observable.type}")
# Test data
test_observables = [
{
"type": "file",
"hashes": {
"MD5": "d41d8cd98f00b204e9800998ecf8427e"
},
"name": "malware.exe",
"size": 75000
},
{
"type": "ipv4-addr",
"value": "192.168.1.100"
},
{
"type": "network-traffic",
"protocols": ["tcp"],
"dst_port": 4444
}
]
# Validate patterns
validate_pattern_against_data(
"[file:hashes.MD5 = 'd41d8cd98f00b204e9800998ecf8427e' AND file:size > 50000]",
test_observables
)Install with Tessl CLI
npx tessl i tessl/pypi-stix2