diff --git a/PLAYBOOKS/Case_L3_SOC_Analyst_Agent.py b/PLAYBOOKS/Case_L3_SOC_Analyst_Agent.py index 1e462e7..38803c1 100644 --- a/PLAYBOOKS/Case_L3_SOC_Analyst_Agent.py +++ b/PLAYBOOKS/Case_L3_SOC_Analyst_Agent.py @@ -9,7 +9,7 @@ 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.sirpmodel import PlaybookJobStatus, PlaybookModel, CaseModel +from PLUGINS.SIRP.sirpmodel import PlaybookJobStatus, PlaybookModel, CaseModel, AttackStage from PLUGINS.SIRP.sirpmodel import Severity, Confidence @@ -22,7 +22,7 @@ class AnalyzeResult(BaseModel): 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: str | dict[str, Any] | None = Field(description="e.g., 'T1059 - Command and Control', 'Lateral Movement'", 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) @@ -81,9 +81,9 @@ class Playbook(LanggraphPlaybook): case_new = CaseModel(rowid=self.param_source_rowid, severity_ai=analyze_result.new_severity, confidence_ai=analyze_result.confidence, - analysis_rationale_ai=analyze_result.analysis_rationale, + comment_ai=analyze_result.analysis_rationale, attack_stage_ai=analyze_result.attack_stage, - recommended_actions_ai=analyze_result.recommended_actions, + summary_ai=analyze_result.recommended_actions, ) Case.update(case_new) diff --git a/PLAYBOOKS/Case_L3_SOC_Analyst_Agent_With_Tools.py b/PLAYBOOKS/Case_L3_SOC_Analyst_Agent_With_Tools.py index 1e836e7..6bdc130 100644 --- a/PLAYBOOKS/Case_L3_SOC_Analyst_Agent_With_Tools.py +++ b/PLAYBOOKS/Case_L3_SOC_Analyst_Agent_With_Tools.py @@ -12,7 +12,7 @@ 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.sirpmodel import PlaybookJobStatus, CaseModel, PlaybookModel +from PLUGINS.SIRP.sirpmodel import PlaybookJobStatus, CaseModel, PlaybookModel, AttackStage from PLUGINS.SIRP.sirpmodel import Severity, Confidence @@ -51,9 +51,9 @@ class AnalyzeResult(BaseModel): default=None, description="详细推理过程.需包含识别到的新证据、新旧告警关联逻辑以及搜索工具返回的情报如何辅助了判断." ) - attack_stage: str | None = Field( + attack_stage: AttackStage | None = Field( default=None, - description="参考 MITRE ATT&CK 战术名称,必须是字符串(如:'T1059 - Command and Control', 'Lateral Movement')." + description="MITRE ATT&CK 战术名称(如:'Lateral Movement')." ) recommended_actions: str | None = Field( default=None, @@ -151,9 +151,9 @@ class Playbook(LanggraphPlaybook): case_new = CaseModel(rowid=self.param_source_rowid, severity_ai=analyze_result.new_severity, confidence_ai=analyze_result.confidence, - analysis_rationale_ai=analyze_result.analysis_rationale, + comment_ai=analyze_result.analysis_rationale, attack_stage_ai=analyze_result.attack_stage, - recommended_actions_ai=analyze_result.recommended_actions, + summary_ai=analyze_result.recommended_actions, ) Case.update(case_new) diff --git a/PLUGINS/ClaudeCode/skills/asp-case/SKILL.md b/PLUGINS/ClaudeCode/skills/asp-case/SKILL.md index 192c4b3..9d5b151 100644 --- a/PLUGINS/ClaudeCode/skills/asp-case/SKILL.md +++ b/PLUGINS/ClaudeCode/skills/asp-case/SKILL.md @@ -58,7 +58,7 @@ Ask the user which operation they want to perform: - Total count - For each key alert: title, severity, status, source UID, correlation UID, first seen time, last seen time -**Associated Artifacts** +**Associated Artifacts for each alert** - Total count - For each key artifact: name, value, type, role, reputation score @@ -108,6 +108,7 @@ Total: [count] cases Risk, Managed Externally, Duplicate, Other - `severity_ai` - AI-assessed severity - `confidence_ai` - Unknown, Low, Medium, High, Other +- `attack_stage_ai` - MITRE ATT&CK tactics - `comment_ai` - Markdown content (use #### as top-level heading) - `summary_ai` - Markdown content (use #### as top-level heading) diff --git a/PLUGINS/ClaudeCode/skills/asp-siem/SKILL.md b/PLUGINS/ClaudeCode/skills/asp-siem/SKILL.md index 34b90ec..570e200 100644 --- a/PLUGINS/ClaudeCode/skills/asp-siem/SKILL.md +++ b/PLUGINS/ClaudeCode/skills/asp-siem/SKILL.md @@ -30,7 +30,8 @@ This skill currently focuses on `siem_keyword_search`. More SIEM operations can **Required parameters:** -- `keyword` - Search keyword or keyword list. Can be an IP address, hostname, username, email, hash, process name, domain, or any string. If a list is provided, all keywords are matched with AND semantics +- `keyword` - Search keyword or keyword list. Can be an IP address, hostname, username, email, hash, process name, + domain, or any string. If a list is provided, all keywords are matched with AND semantics - `time_range_start` - Start time in UTC ISO8601 format, for example `2026-02-04T06:00:00Z` - `time_range_end` - End time in UTC ISO8601 format, for example `2026-02-04T07:00:00Z` @@ -48,11 +49,13 @@ This skill currently focuses on `siem_keyword_search`. More SIEM operations can 3. If the target source uses a non-default time field, collect `time_field`; otherwise use `@timestamp` 4. Use MCP tool `siem_keyword_search` with the collected parameters 5. Check the returned `status` for each result group -6. If the result is too large, reduce the time range or add more precise keywords so the query moves from `summary` or `sample` toward `full` +6. If the result is too large, reduce the time range or add more precise keywords so the query moves from `summary` or + `sample` toward `full` 7. If the result is empty or too narrow, expand the time range or remove restrictive keywords 8. Continue iterating until `full` is reached when the goal is to retrieve the complete original raw logs 9. Parse each returned JSON string -10. If the result list is empty after reasonable refinement, state that no matching logs were found in the specified time range +10. If the result list is empty after reasonable refinement, state that no matching logs were found in the specified + time range 11. Present results grouped by backend and index when multiple results are returned **Behavior notes:** @@ -64,7 +67,8 @@ This skill currently focuses on `siem_keyword_search`. More SIEM operations can - `sample` - statistics plus representative sample records for medium result sets - `summary` - statistics only for large result sets - Use time range changes together with keyword changes to control result volume and converge on `full` -- The preferred end state for evidence collection is `full`, because it contains the complete original raw logs returned by the backend +- The preferred end state for evidence collection is `full`, because it contains the complete original raw logs returned + by the backend - Time values must be UTC and end with `Z` **Refinement guidance:** @@ -118,4 +122,5 @@ Then provide statistics and sample records under each result group. 2. Collect required parameters for the chosen operation 3. Execute the appropriate MCP tool 4. Format and present the results according to the operation's output specification -5. Handle errors gracefully, such as invalid UTC time format, unsupported index, backend connection issues, or no matching logs +5. Handle errors gracefully, such as invalid UTC time format, unsupported index, backend connection issues, or no + matching logs diff --git a/PLUGINS/MCP/llmfunc.py b/PLUGINS/MCP/llmfunc.py index 82fbeac..bd7204c 100644 --- a/PLUGINS/MCP/llmfunc.py +++ b/PLUGINS/MCP/llmfunc.py @@ -5,7 +5,7 @@ from PLUGINS.SIEM.models import KeywordSearchInput from PLUGINS.SIEM.tools import SIEMToolKit from PLUGINS.SIRP.nocolymodel import Group, Condition, Operator from PLUGINS.SIRP.sirpapi import Case -from PLUGINS.SIRP.sirpmodel import CaseModel, Severity, CaseStatus, CaseVerdict, Confidence +from PLUGINS.SIRP.sirpmodel import CaseModel, Severity, CaseStatus, CaseVerdict, Confidence, AttackStage def get_case( @@ -22,6 +22,7 @@ def get_case( def list_cases( status: Annotated[Optional[list[CaseStatus]], "Filter by case status or a list of case statuses"] = None, severity: Annotated[Optional[list[Severity]], "Filter by severity level or a list of severity levels"] = None, + confidence: Annotated[Optional[list[Confidence]], "Filter by severity level or a list of severity levels"] = None, limit: Annotated[int, "Maximum number of results to return"] = 10 ) -> Annotated[list[str], "Security cases matching the filters"]: """List security cases with optional filters.""" @@ -29,9 +30,10 @@ def list_cases( if status: conditions.append(Condition(field="status", operator=Operator.IN, value=status)) - if severity: conditions.append(Condition(field="severity", operator=Operator.IN, value=severity)) + if confidence: + conditions.append(Condition(field="confidence", operator=Operator.IN, value=confidence)) filter_model = Group(logic="AND", children=conditions) if conditions else Group(logic="AND", children=[]) @@ -44,11 +46,12 @@ def list_cases( def update_case( case_id: Annotated[str, "Case ID to update"], - severity: Annotated[Optional[str], "New severity"] = None, - status: Annotated[Optional[str], "New status"] = None, - verdict: Annotated[Optional[str], "New verdict"] = None, - severity_ai: Annotated[Optional[str], "New AI-assessed severity"] = None, - confidence_ai: Annotated[Optional[str], "New AI-assessed confidence"] = None, + severity: Annotated[Optional[Severity], "New severity"] = None, + status: Annotated[Optional[CaseStatus], "New status"] = None, + verdict: Annotated[Optional[CaseVerdict], "New verdict"] = None, + severity_ai: Annotated[Optional[Severity], "New AI-assessed severity"] = None, + confidence_ai: Annotated[Optional[Confidence], "New AI-assessed confidence"] = None, + attack_stage_ai: Annotated[Optional[AttackStage], "New AI-attack stage"] = None, comment_ai: Annotated[Optional[ str], "New AI-comment. Supports Markdown format."] = None, summary_ai: Annotated[Optional[ @@ -62,16 +65,17 @@ def update_case( case_new = CaseModel() case_new.rowid = case_old.rowid if severity: - case_new.severity = Severity(severity) + case_new.severity = severity if status: - case_new.status = CaseStatus(status) + case_new.status = status if verdict: - case_new.verdict = CaseVerdict(verdict) + case_new.verdict = verdict if severity_ai: - case_new.severity_ai = Severity(severity_ai) + case_new.severity_ai = severity_ai if confidence_ai: - case_new.confidence_ai = Confidence(confidence_ai) - + case_new.confidence_ai = confidence_ai + if attack_stage_ai: + case_new.attack_stage_ai = attack_stage_ai if comment_ai: case_new.comment_ai = comment_ai if summary_ai: diff --git a/PLUGINS/SIRP/sirpmodel.py b/PLUGINS/SIRP/sirpmodel.py index d72b78e..4c8f393 100644 --- a/PLUGINS/SIRP/sirpmodel.py +++ b/PLUGINS/SIRP/sirpmodel.py @@ -138,6 +138,23 @@ class Severity(StrEnum): OTHER = "Other" +class AttackStage(StrEnum): + RECONNAISSANCE = "Reconnaissance" + RESOURCE_DEVELOPMENT = "Resource Development" + INITIAL_ACCESS = "Initial Access" + EXECUTION = "Execution" + PERSISTENCE = "Persistence" + PRIVILEGE_ESCALATION = "Privilege Escalation" + DEFENSE_EVASION = "Defense Evasion" + CREDENTIAL_ACCESS = "Credential Access" + DISCOVERY = "Discovery" + LATERAL_MOVEMENT = "Lateral Movement" + COLLECTION = "Collection" + COMMAND_AND_CONTROL = "Command and Control" + EXFILTRATION = "Exfiltration" + IMPACT = "Impact" + + class ImpactLevel(StrEnum): UNKNOWN = "Unknown" LOW = "Low" @@ -697,7 +714,7 @@ class CaseModel(BaseSystemModel): workbook: Optional[str] = Field(default="", description="事件调查使用的工作簿或调查手册内容") # ai 字段 - attack_stage_ai: Optional[str] = Field(default="", description="AI评估的攻击阶段") + attack_stage_ai: Optional[AttackStage] = Field(default="", description="AI评估的攻击阶段") severity_ai: Optional[Severity] = Field(default=None, description="AI评估的事件严重性") confidence_ai: Optional[Confidence] = Field(default=None, description="AI评估的事件置信度")