"""ThreatActor and ThreatActorTechnique models. Stores profiles of APT groups and their associated MITRE ATT&CK techniques, imported from MITRE CTI (STIX 2.0). """ # Import uuid import uuid # Import from sqlalchemy from sqlalchemy import ( Boolean, Column, DateTime, ForeignKey, Index, String, Text, UniqueConstraint, func, ) # Import JSONB, UUID from sqlalchemy.dialects.postgresql from sqlalchemy.dialects.postgresql import JSONB, UUID # Import relationship from sqlalchemy.orm from sqlalchemy.orm import relationship # Import Base from app.database from app.database import Base # Define class ThreatActor class ThreatActor(Base): """Threat actor / APT group profile. Imported from MITRE CTI ``intrusion-set`` STIX objects. """ # Assign __tablename__ = "threat_actors" __tablename__ = "threat_actors" # Assign id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4) id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4) # Assign mitre_id = Column(String, unique=True, nullable=True) # e.g. "G00... mitre_id = Column(String, unique=True, nullable=True) # e.g. "G0016" (APT29) # Assign name = Column(String, nullable=False) name = Column(String, nullable=False) # Assign aliases = Column(JSONB, nullable=True, default=[]) # ["Cozy ... aliases = Column(JSONB, nullable=True, default=[]) # ["Cozy Bear", "The Dukes", ...] # Assign description = Column(Text, nullable=True) description = Column(Text, nullable=True) # Assign country = Column(String, nullable=True) country = Column(String, nullable=True) # Assign target_sectors = Column(JSONB, nullable=True, default=[]) # ["government",... target_sectors = Column(JSONB, nullable=True, default=[]) # ["government", "defense", ...] # Assign target_regions = Column(JSONB, nullable=True, default=[]) # ["north-americ... target_regions = Column(JSONB, nullable=True, default=[]) # ["north-america", "europe", ...] # Assign motivation = Column(String, nullable=True) # espionage ... motivation = Column(String, nullable=True) # espionage / financial / destruction / ... # Assign sophistication = Column(String, nullable=True) # low / medium /... sophistication = Column(String, nullable=True) # low / medium / high / advanced # Assign first_seen = Column(String, nullable=True) first_seen = Column(String, nullable=True) # Assign last_seen = Column(String, nullable=True) last_seen = Column(String, nullable=True) # Assign references = Column(JSONB, nullable=True, default=[]) # [{"url": "... references = Column(JSONB, nullable=True, default=[]) # [{"url": "...", "description": "..."}] # Assign mitre_url = Column(String, nullable=True) mitre_url = Column(String, nullable=True) # Assign is_active = Column(Boolean, default=True) is_active = Column(Boolean, default=True) # Assign created_at = Column(DateTime(timezone=True), server_default=func.now()) created_at = Column(DateTime(timezone=True), server_default=func.now()) # Relationships techniques = relationship( # Literal argument value "ThreatActorTechnique", # Keyword argument: back_populates back_populates="threat_actor", # Keyword argument: cascade cascade="all, delete-orphan", ) # Assign __table_args__ = ( __table_args__ = ( Index('ix_threat_actors_country', 'country'), Index('ix_threat_actors_motivation', 'motivation'), ) # Define class ThreatActorTechnique class ThreatActorTechnique(Base): """Association between a threat actor and a MITRE ATT&CK technique. Stores additional context about how the actor uses the technique (from the STIX ``relationship`` ``uses`` objects). """ # Assign __tablename__ = "threat_actor_techniques" __tablename__ = "threat_actor_techniques" # Assign id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4) id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4) # Assign threat_actor_id = Column( threat_actor_id = Column( UUID(as_uuid=True), ForeignKey("threat_actors.id", ondelete="CASCADE"), # Keyword argument: nullable nullable=False, ) # Assign technique_id = Column( technique_id = Column( UUID(as_uuid=True), ForeignKey("techniques.id", ondelete="CASCADE"), # Keyword argument: nullable nullable=False, ) # Assign usage_description = Column(Text, nullable=True) usage_description = Column(Text, nullable=True) # Assign first_seen_using = Column(String, nullable=True) first_seen_using = Column(String, nullable=True) # Relationships threat_actor = relationship("ThreatActor", back_populates="techniques") # Assign technique = relationship("Technique") technique = relationship("Technique") # Assign __table_args__ = ( __table_args__ = ( Index('ix_threat_actor_techniques_actor', 'threat_actor_id'), Index('ix_threat_actor_techniques_technique', 'technique_id'), UniqueConstraint( # Literal argument value 'threat_actor_id', 'technique_id', # Keyword argument: name name='uq_actor_technique', ), )