This commit is contained in:
rookit
2026-04-27 15:27:19 +08:00
parent 977f7a71d8
commit 432243493d
10 changed files with 150 additions and 75 deletions
@@ -0,0 +1,3 @@
你是一位顶尖的网络安全AI分析专家,深谙MITRE ATT&CK框架及安全事件关联分析.
你的核心目标是解析输入的结构化安全事件数据,进行深度的技术推理与逻辑重组,并将其提炼为高度结构化的专业事件调查报告.
你必须利用提供的工具和Schema结构化你的输出,严格遵守各个字段的描述要求进行精准的信息提取,切勿捏造未在原始数据中出现的证据.
@@ -98,7 +98,6 @@ class Module(LanggraphModule):
analytic_type=AlertAnalyticType.BEHAVIORAL,
product_category=ProductCategory.NDR,
product_name="Network Detection & Response",
first_seen_time=alert_date_formatted,
desc=description,
data_sources=["NDR"],
labels=tags + ["c2-communication"],
+115
View File
@@ -0,0 +1,115 @@
from typing import Any
from typing import List, Dict, Optional
from langchain_core.messages import HumanMessage
from pydantic import BaseModel, Field
from pydantic import ConfigDict
from Lib.baseplaybook import BasePlaybook
from PLUGINS.LLM.llmapi import LLMAPI
from PLUGINS.SIRP.sirpapi import Case
from PLUGINS.SIRP.sirpcoremodel import Severity, AttackStage, Confidence
from PLUGINS.SIRP.sirpextramodel import PlaybookModel
class AnalyzeResult(BaseModel):
"""Structure for extracting user information from text"""
# config
model_config = ConfigDict(use_enum_values=True)
original_severity: Severity = Field(description="Original alert severity")
new_severity: Severity = Field(description="Recommended new severity level")
confidence: Confidence = Field(description="Confidence score, only one of 'Low', 'Medium', or 'High'")
analysis_rationale: str | None = Field(description="Analysis process and reasons", default=None)
attack_stage: AttackStage = Field(description="e.g. 'Lateral Movement'", default=None)
recommended_actions: str | dict[str, Any] | None = Field(description="e.g., 'Isolate host 10.1.1.5'", default=None)
class AffectedAsset(BaseModel):
asset_type: str = Field(description="资产的类型, 例如Host, IP, User, File, Cloud Resource.")
asset_value: str = Field(description="资产的具体标识符, 例如IP地址, 主机名, 用户名, 资源ARN.")
class ArtifactAnalysis(BaseModel):
artifact_name: str = Field(description="痕迹或载荷的标识符, 例如文件名, 进程名, URL或IAM角色名.")
artifact_type: str = Field(description="痕迹的类型, 例如File, Process, Network Traffic, API Call, IAM Policy.")
properties: Dict[str, str] = Field(
description="动态属性键值对. 根据痕迹类型提取不同的关键属性, 例如文件可能包含MD5, Path; 网络请求可能包含Method, User-Agent; 云操作可能包含API Name, Parameters.")
analysis_result: str = Field(description="对该痕迹的深度技术分析, 解释其执行的恶意行为, 功能机制以及造成的威胁等级.")
threat_intelligence: Optional[str] = Field(description="与该痕迹相关的威胁情报信息或标签, 如无则为空.")
class AttackChainStep(BaseModel):
phase: str = Field(description="攻击链的阶段名称, 例如Initial Access, Execution, Persistence, Privilege Escalation, Lateral Movement等.")
description: str = Field(description="该阶段的具体行为说明, 描述攻击者如何利用漏洞或执行了什么操作.")
class TimelineEvent(BaseModel):
timestamp: str = Field(description="事件发生的时间点.")
attack_behavior: str = Field(description="在该时间点发生的具体攻击行为或检测到的动作.")
evidence_field: str = Field(description="支撑该行为判断的关键证据字段或日志内容片段.")
class IndicatorOfCompromise(BaseModel):
indicator_type: str = Field(description="IOC的类型, 必须从以下范围中选择: IP, Domain, URL, FileHash, FilePath, Command, RegistryKey.")
value: str = Field(description="IOC的具体值, 例如具体的IP地址, MD5字符串或恶意文件路径.")
confidence: str = Field(description="该指标的置信度或威胁等级, 例如High, Medium, Low.")
context: str = Field(description="简述该IOC在本次事件中的上下文描述, 例如作为C2服务器建立网络连接或被释放的后门文件.")
class RemediationRecommendation(BaseModel):
action_type: str = Field(description="处置或加固动作的类型, 例如隔离主机, 封禁IP, 清除文件, 修复漏洞等.")
description: str = Field(description="具体的处置步骤或系统加固建议说明.")
priority: str = Field(description="该建议的执行优先级, 例如High, Medium, Low.")
class IncidentReport(BaseModel):
digest: str = Field(description="事件的综合摘要. 需确认攻击是否真实发生, 攻击者获取的最高权限, 核心恶意行为以及总体的影响评估.")
affected_assets: List[AffectedAsset] = Field(description="受此次事件影响或作为目标的资产列表.")
attack_chain_description: List[AttackChainStep] = Field(description="按时间或逻辑顺序重建的攻击链结构化步骤列表.")
artifact_analysis: List[ArtifactAnalysis] = Field(description="对事件中的关键痕迹或恶意载荷的详细分析列表. 利用properties字段动态适应不同类型的告警特征.")
attack_timeline: List[TimelineEvent] = Field(description="按时间顺序排列的事件时间线.")
ioc_indicators: List[IndicatorOfCompromise] = Field(description="结构化提取的妥协指标列表.")
remediation_recommendations: List[RemediationRecommendation] = Field(description="针对该事件的处置与系统加固建议列表.")
class Playbook(BasePlaybook):
NAME = "Investigation Agent"
DESC = "Investigation Agent"
def __init__(self):
super().__init__() # do not delete this code
def run(self):
case = Case.get(self.param_source_row_id)
content = case.model_dump_json_for_ai()
# Load system prompt
system_message = self.load_system_prompt_template("L3_SOC_Analyst").format()
# Run
llm_api = LLMAPI()
llm = llm_api.get_model(tag="structured_output")
# Construct message list
messages = [
system_message,
HumanMessage(content=content)
]
llm = llm.with_structured_output(IncidentReport)
response = llm.invoke(messages)
response: IncidentReport
return
if __name__ == "__main__":
import os
import django
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "ASP.settings")
django.setup()
model = PlaybookModel(source_row_id='b6383d3f-bbdc-432b-9ac7-debb25535617')
module = Playbook()
module._playbook_model = model
module.run()
+1 -1
View File
@@ -9,8 +9,8 @@ from Lib.baseplaybook import LanggraphPlaybook
from Lib.llmapi import BaseAgentState
from PLUGINS.LLM.llmapi import LLMAPI
from PLUGINS.SIRP.sirpapi import Case
from PLUGINS.SIRP.sirpextramodel import PlaybookJobStatus, PlaybookModel
from PLUGINS.SIRP.sirpcoremodel import Severity, AttackStage, Confidence, CaseModel
from PLUGINS.SIRP.sirpextramodel import PlaybookJobStatus, PlaybookModel
class AnalyzeResult(BaseModel):
@@ -41,7 +41,7 @@ ASP 的内部 Knowledge 本质上是一条一条数据库记录,核心字段
## 运行规则
- 把它视为知识检索与维护工具,而不是通用聊天记忆。
- 如果用户是在“找相关知识内容”,尤其是给出主题、问题描述、症状、案特征、短语或自然语言查询,优先使用 `search_knowledge`
- 如果用户是在“找相关知识内容”,尤其是给出主题、问题描述、症状、案特征、短语或自然语言查询,优先使用 `search_knowledge`
- 如果用户是在“查数据库里有哪些 knowledge 记录”或“按字段过滤某些记录”,使用 `list_knowledge`
- 如果用户是在维护某条记录的标题、正文、标签或处理动作,使用 `update_knowledge`
- 不要把 `using` 当作可直接更新的字段;它是系统处理后的结果状态。
@@ -84,7 +84,7 @@ self.read_stream_message()
## SIRP 数据层级
```
Case(调查案,顶层)
Case(调查案,顶层)
│ 通过 correlation_uid 聚合同类告警
└── Alert(单次规则触发记录,二级)
-16
View File
@@ -160,21 +160,6 @@ def get_alert_discussions(
return [json.dumps(item, ensure_ascii=False) for item in discussions]
def update_alert(
alert_id: Annotated[str, Field(description="Alert ID to update (待更新的 Alert ID)")],
severity_ai: Annotated[Severity, Field(description="Updated AI-assessed severity (更新 AI 评估严重程度)")] = None,
confidence_ai: Annotated[Optional[Confidence], Field(description="Updated AI-assessed confidence (更新 AI 评估置信度)")] = None,
comment_ai: Annotated[Optional[str], Field(description="Updated AI comment, Markdown supported (更新 AI 注释,支持 Markdown)")] = None
) -> Annotated[Optional[str], Field(description="Updated alert row ID, or None if not found (更新后的 Alert 行 ID,不存在时返回 None)")]:
"""Update AI-assessed fields on an alert. (更新 Alert 的 AI 评估字段)"""
return Alert.update_by_id(
alert_id=alert_id,
severity_ai=severity_ai,
confidence_ai=confidence_ai,
comment_ai=comment_ai
)
# Artifact
# Do not open to mcp , because we think artifact is add only by automation, not human
def create_artifact(
@@ -561,7 +546,6 @@ REGISTERED_MCP_TOOLS = [
# alert
list_alerts,
get_alert_discussions,
update_alert,
# artifact
list_artifacts,
-23
View File
@@ -512,29 +512,6 @@ class Alert(BaseWorksheetEntity[AlertModel]):
else:
return None
@classmethod
def update_by_id(
cls,
alert_id: str,
severity_ai: Union[Severity, None] = None,
confidence_ai: Union[Confidence, None] = None,
comment_ai: Union[str, None] = None
) -> Union[str, None]:
alert_old = cls.get_by_id(alert_id, lazy_load=True)
if not alert_old:
return None
alert_new = AlertModel()
alert_new.row_id = alert_old.row_id
if severity_ai is not None:
alert_new.severity_ai = severity_ai
if confidence_ai is not None:
alert_new.confidence_ai = confidence_ai
if comment_ai is not None:
alert_new.comment_ai = comment_ai
return cls.update(alert_new)
@classmethod
def get_discussions(cls, alert_id) -> Union[List[dict], None]:
alert_model = cls.get_by_id(alert_id, lazy_load=True)
+27 -30
View File
@@ -284,6 +284,7 @@ class CaseVerdict(StrEnum):
class EnrichmentModel(BaseSystemModel):
"""Artifact/Alert/Case结构化的富化信息"""
_AI_EXCLUDE_FIELDS: ClassVar[set[str]] = set()
id: Optional[str] = Field(default=None, init=False, description="Record ID e.g. enrichment_000001 (记录 ID e.g. enrichment_000001)")
name: Optional[str] = Field(default="", description="Enrichment name (富化名称)")
@@ -296,6 +297,7 @@ class EnrichmentModel(BaseSystemModel):
class TicketModel(BaseSystemModel):
"""关联到Case的外部工单信息"""
_AI_EXCLUDE_FIELDS: ClassVar[set[str]] = {'case'}
id: Optional[str] = Field(default=None, init=False, description="Record ID e.g. ticket_000001 (记录 ID e.g. ticket_000001)")
@@ -308,11 +310,11 @@ class TicketModel(BaseSystemModel):
src_url: Optional[str] = Field(default="", description="External ticket URL (外部工单 URL)")
# 反向关联,无需手动处理
case: Optional[List[Union[CaseModel, str]]] = Field(default=None, init=False, description="Linked case row_id (关联案行 ID)")
case: Optional[List[Union[CaseModel, str]]] = Field(default=None, init=False, description="Linked case row_id (关联案行 ID)")
class ArtifactModel(BaseSystemModel):
"""Stores entity information extracted from alerts, the minimum investigatable unit"""
"""Entity information extracted from alerts, the minimum investigate unit"""
_AI_EXCLUDE_FIELDS: ClassVar[set[str]] = {'alert'}
# 系统自动生成字段
id: Optional[str] = Field(default=None, init=False, description="Record ID e.g. artifact_000001 (记录 ID e.g. artifact_000001)")
@@ -336,7 +338,8 @@ class ArtifactModel(BaseSystemModel):
class AlertModel(BaseSystemModel):
_AI_EXCLUDE_FIELDS: ClassVar[set[str]] = {'raw_data', 'severity_ai', 'confidence_ai', "impact_ai", "comment_ai", "case"}
"""基础告警信息,通常与SIEM Rule 产生的告警进行映射, 是连接 SIEM 告警与 SIRP 案件的核心数据模型"""
_AI_EXCLUDE_FIELDS: ClassVar[set[str]] = {'raw_data', "case"}
# 系统自动生成字段
id: Optional[str] = Field(default=None, init=False,
@@ -395,47 +398,41 @@ class AlertModel(BaseSystemModel):
raw_data: Optional[str] = Field(default="", description="Raw alert log JSON (原始告警日志 JSON)")
# AI字段
severity_ai: Optional[Severity] = Field(default=None, description="AI-assessed severity (AI 评估严重程度)")
confidence_ai: Optional[Confidence] = Field(default=None, description="AI-assessed confidence (AI 评估置信度)")
impact_ai: Optional[Impact] = Field(default=Impact.UNKNOWN, description="AI-assessed potential impact (AI 评估潜在影响)")
risk_level_ai: Optional[AlertRiskLevel] = Field(default=None, description="Assessed risk level (AI 评估的风险等级)")
comment_ai: Optional[str] = Field(default="", description="AI-generated comment (AI 生成的注释)")
# 反向关联,无需手动处理
case: Optional[List[Union[CaseModel, str]]] = Field(default=None, init=False,
description="Linked case row_id, reverse association, auto-linked, no manual setting needed (关联案行 ID,反向关联,自动化关联,无需手动设置)")
description="Linked case row_id, reverse association, auto-linked, no manual setting needed (关联案行 ID,反向关联,自动化关联,无需手动设置)")
# 关联表
artifacts: Optional[List[Union[ArtifactModel, str]]] = Field(default=None, description="Extracted artifacts (关联表, 提取的实体列表)")
enrichments: Optional[List[Union[EnrichmentModel, str]]] = Field(default=None, description="Alert enrichments (关联表, 告警富化)")
class CaseModel(BaseSystemModel):
"""安全案件,多个告警聚合而成,安全人员与AI分析处理的核心对象"""
_AI_EXCLUDE_FIELDS: ClassVar[set[str]] = {"workbook", "summary_ai", "comment_ai", "attack_stage_ai", "severity_ai", "confidence_ai", "impact_ai",
"priority_ai", "verdict_ai"}
# 系统自动生成字段
id: Optional[str] = Field(default=None, init=False, description="Record ID e.g. case_000001 (记录 ID e.g. case_000001,系统自动生成,无需手动赋值)")
# 创建记录填写字段
title: Optional[str] = Field(default="", description="Case title (案标题)")
title: Optional[str] = Field(default="", description="Case title (案标题)")
severity: Optional[Severity] = Field(default=None, description="Analyst-assessed severity (严重程度)")
impact: Optional[Impact] = Field(default=None, description="Analyst-assessed impact (影响)")
priority: Optional[CasePriority] = Field(default=None, description="Response priority (响应优先级)")
confidence: Optional[Confidence] = Field(default=None, description="Analyst-assessed confidence (分析师评估置信度)")
description: Optional[str] = Field(default="", description="Case description (案描述)")
description: Optional[str] = Field(default="", description="Case description (案描述)")
category: Optional[ProductCategory] = Field(default=None, description="Case category (案类别)")
tags: Optional[List[str]] = Field(default=[], description="Case tags (案标签)", json_schema_extra={"type": 2})
category: Optional[ProductCategory] = Field(default=None, description="Case category (案类别)")
tags: Optional[List[str]] = Field(default=[], description="Case tags (案标签)", json_schema_extra={"type": 2})
correlation_uid: Optional[str] = Field(default="", description="Case correlation ID (案关联 ID)")
correlation_uid: Optional[str] = Field(default="", description="Case correlation ID (案关联 ID)")
# 用户手动输入字段
status: Optional[CaseStatus] = Field(default=CaseStatus.NEW, description="Case handling status (案处理状态)")
status: Optional[CaseStatus] = Field(default=CaseStatus.NEW, description="Case handling status (案处理状态)")
acknowledged_time: Optional[AutoDatetime] = Field(default=None, description="L1 first acknowledged time (L1 首次接手时间)")
assignee_l1: Optional[AutoAccount] = Field(default=None, description="Assigned L1 analyst (分配的 L1 分析师)")
comment: Optional[str] = Field(default="", description="Case analyst comment (案分析师注释)")
comment: Optional[str] = Field(default="", description="Case analyst comment (案分析师注释)")
assignee_l2: Optional[AutoAccount] = Field(default=None, description="Assigned or escalated L2 analyst (分配或升级的 L2 分析师)")
assignee_l3: Optional[AutoAccount] = Field(default=None, description="Assigned or escalated L3 analyst (分配或升级的 L3 分析师)")
@@ -444,18 +441,7 @@ class CaseModel(BaseSystemModel):
verdict: Optional[CaseVerdict] = Field(default=None, description="Final verdict (最终判定结果)")
summary: Optional[str] = Field(default="", description="Closure summary (结案摘要)")
# ai 字段
severity_ai: Optional[Severity] = Field(default=None, description="AI-assessed severity (AI 评估严重程度)")
confidence_ai: Optional[Confidence] = Field(default=None, description="AI-assessed confidence (AI 评估置信度)")
impact_ai: Optional[Impact] = Field(default=None, description="AI-assessed impact (AI 评估影响)")
priority_ai: Optional[CasePriority] = Field(default=None, description="AI-assessed response priority (AI 评估响应优先级)")
attack_stage_ai: Optional[AttackStage] = Field(default="", description="AI-assessed attack stage (AI 评估攻击阶段)")
comment_ai: Optional[str] = Field(default="", description="AI-generated comment (AI 生成的注释)")
verdict_ai: Optional[CaseVerdict] = Field(default=None, description="AI-generated final verdict (AI 生成的最终判定结果)")
summary_ai: Optional[str] = Field(default="", description="AI-generated closure summary (AI 生成的结案摘要)")
# 自动计算字段,无需手动赋值
start_time_calc: Optional[AutoDatetime] = Field(default=None, description="Calculated start time (计算的开始时间)")
end_time_calc: Optional[AutoDatetime] = Field(default=None, description="Calculated end time (计算的结束时间)")
detect_time_calc: Optional[Any] = Field(default=None, description="Calculated detect time (计算的检测时间)")
@@ -464,5 +450,16 @@ class CaseModel(BaseSystemModel):
# 关联表
tickets: Optional[List[Union[TicketModel, str]]] = Field(default=None, description="Linked external tickets (关联外部工单)")
enrichments: Optional[List[Union[EnrichmentModel, str]]] = Field(default=None, description="Case enrichments (案富化)")
enrichments: Optional[List[Union[EnrichmentModel, str]]] = Field(default=None, description="Case enrichments (案富化)")
alerts: Optional[List[Union[AlertModel, str]]] = Field(default=None, description="Linked alerts (关联的告警)")
# ai 字段
severity_ai: Optional[Severity] = Field(default=None, description="AI-assessed severity (AI 评估严重程度)")
confidence_ai: Optional[Confidence] = Field(default=None, description="AI-assessed confidence (AI 评估置信度)")
impact_ai: Optional[Impact] = Field(default=None, description="AI-assessed impact (AI 评估影响)")
priority_ai: Optional[CasePriority] = Field(default=None, description="AI-assessed response priority (AI 评估响应优先级)")
attack_stage_ai: Optional[AttackStage] = Field(default="", description="AI-assessed attack stage (AI 评估攻击阶段)")
comment_ai: Optional[str] = Field(default="", description="AI-generated comment (AI 生成的注释)")
verdict_ai: Optional[CaseVerdict] = Field(default=None, description="AI-generated final verdict (AI 生成的最终判定结果)")
summary_ai: Optional[str] = Field(default="", description="AI-generated closure summary (AI 生成的结案摘要)")
+2 -2
View File
@@ -43,8 +43,8 @@ ASP 通过简化的多阶段流程处理安全告警和事件:
2. **Webhook 转发器**SIEM 通过 Webhook 将这些告警转发到 ASP 内置的 Webhook 接收器。
3. **Redis Stream**:接收器将告警推送到相应的 Redis Stream 中,作为持久化消息队列。每种告警类型都有自己的流。
4. **模块引擎**:ASP **模块**从其指定的流中消费告警,执行分析(通常使用 AI Agent)、丰富数据,并确定结果。
5. **SIRP 平台**:模块的输出(现已格式化为标准化的安全记录)被发送到 **SIRP** 平台,在那里创建或更新案、告警和 Artifact。
6. **剧本引擎**:分析师可以从 SIRP 用户界面触发针对案、告警或 Artifact 的 **剧本**,以执行进一步的自动化操作,例如威胁情报丰富或修复。
5. **SIRP 平台**:模块的输出(现已格式化为标准化的安全记录)被发送到 **SIRP** 平台,在那里创建或更新案、告警和 Artifact。
6. **剧本引擎**:分析师可以从 SIRP 用户界面触发针对案、告警或 Artifact 的 **剧本**,以执行进一步的自动化操作,例如威胁情报丰富或修复。
![img_1.webp](Docker/IMG/img_20.png)
![img_2.webp](Docker/IMG/img_21.png)