Sorakurai/karasu

GitHub: Sorakurai/karasu

基于 LLM 的威胁情报自动化平台,从 URL 中提取结构化情报并发布到 MISP,通过人工审核保障情报质量。

Stars: 1 | Forks: 0

# Karasu 一个威胁情报自动化平台,能够导入 URL,使用 LLM 提取结构化情报,支持分析师审核,并将结果作为 MISP 事件发布。 ## 目录 - [概述](#overview) - [架构](#architecture) - [入门指南](#getting-started) - [开发(不使用 Docker)](#development-without-docker) - [添加自定义 LLM 提供商](#adding-a-custom-llm-provider) - [设计决策](#design-decisions) ## 概述 分析师提交一个 URL(威胁报告、博客文章、PDF)。平台获取内容,通过 LLM 提取结构化威胁情报,并将结果显示在编辑器中供审核。满意后,分析师将事件直接推送到 MISP 实例。 ### 流水线 ``` URL submitted → Fetch content → LLM extraction → Analyst review → Push to MISP ``` ### 提取的情报 | 类别 | 详情 | |---|---| | 摘要 | 威胁的简短描述 | | 威胁行为者 | 具名组织或个人 | | 目标行业 | 受到攻击的行业或部门 | | 目标国家 | 受到攻击的国家 | | IoCs | IP、域名、URL、MD5 / SHA1 / SHA256 哈希值(带有 `to_ids` 标志) | | TTPs | MITRE ATT&CK 技术 ID、名称和上下文 | | 检测规则 | 引擎(Sigma、KQL 等)和查询语句 | | 威胁狩猎假设 | 标题、假设、方法和可见性 | ### MISP 事件结构 | 情报 | MISP 表示 | |---|---| | IoCs | 带类型的属性(`ip-dst`、`domain`、`url`、`md5`、`sha1`、`sha256`) | | 威胁行为者 | `threat-actor` 属性 | | 目标行业 | `target-org` 属性 | | 目标国家 | `target-location` 属性 | | TTPs | Galaxy 标签(`misp-galaxy:mitre-attack-pattern`)+ `attack-pattern` 对象 | | 检测规则 | 带引擎注释的 `text` 属性 | | 威胁狩猎假设 | 事件报告(Markdown,标记为 `Threat Hunting Hypothesis`) | ## 架构 ``` ┌─────────────┐ ┌─────────────┐ ┌──────────────┐ │ Frontend │────▶│ Backend │────▶│ PostgreSQL │ │ React/Vite │ │ FastAPI │ └──────────────┘ │ (nginx) │ │ (Uvicorn) │ ┌──────────────┐ └─────────────┘ └──────┬──────┘────▶│ Redis │ │ └──────────────┘ ┌──────▼──────────────────────────────┐ │ Celery Workers │ │ ┌─────────┐ ┌─────────┐ ┌──────┐ │ │ │ fetch │ │ extract │ │ misp │ │ │ └────┬────┘ └────┬────┘ └──┬───┘ │ └───────┼───────────┼──────────┼──────┘ │ │ │ fetch page LLM provider MISP content (pluggable) galaxy │ resolution ▼ │ ┌──────────┐ ▼ │ Azure AI │ ┌─────────┐ │ Foundry │ │ MISP │ └──────────┘ └─────────┘ ``` **处理流水线** ``` URL submitted → [fetch] → [extract] → Analyst review → [misp] → MISP event published ``` **服务** | 服务 | 角色 | |---|---| | `frontend` | 由 nginx 提供服务的 React SPA,将 `/api` 代理到后端 | | `backend` | FastAPI REST API,JWT 认证,业务逻辑 | | `celery` | 消费 fetch、extract 和 misp 队列的后台工作进程 | | `postgres` | URL、原始内容和提取情报的主数据存储 | | `redis` | Celery 代理和结果后端 | **Celery 队列** | 队列 | 任务 | 描述 | |---|---|---| | `fetch` | `fetch_url_task` | 下载 URL 内容(HTML、PDF)并存储原始文本 | | `extract` | `extract_llm_task` | 运行 LLM 提取;在达到 token 限制时回退到拆分提取 | | `misp` | `push_to_misp_task` | 解析 ATT&CK galaxy 标签并将事件发布到 MISP | **LLM 抽象** LLM 提供商可通过环境中的 `LLM_PROVIDER` 进行插拔式配置。当前生效的提供商在运行时由 `backend/app/services/llm/factory.py` 中的工厂进行选择。有关实现细节,请参阅[添加自定义 LLM 提供商](#adding-a-custom-llm-provider)。 ## 入门指南 ### 前置条件 - Docker 和 Docker Compose - 已导入 MITRE ATT&CK galaxy 的运行中的 MISP 实例 - LLM 提供商(默认:使用 Mistral Small 2503 的 Azure AI Foundry) ### 1. 配置环境 复制示例文件并填入相应的值: ``` cp backend/.env.example backend/.env ``` 所有必需的值都列在 `.env.example` 中,并在适用处提供了生成说明。关键值如下: | 变量 | 描述 | 如何生成 | |---|---|---| | `POSTGRES_PASSWORD` | 数据库密码 | 选择一个强密码 | | `SECRET_KEY` | 应用程序密钥 | `python -c "import secrets; print(secrets.token_hex(32))"` | | `JWT_SECRET_KEY` | JWT 签名密钥 | `python -c "import secrets; print(secrets.token_hex(32))"` | | `MISP_TOKEN_ENCRYPTION_KEY` | 用于静态加密 MISP token 的 Fernet 密钥 | `python -c "from cryptography.fernet import Fernet; print(Fernet.generate_key().decode())"` | | `AZURE_API_KEY` | Azure AI Foundry API 密钥 | Azure 门户 | | `AZURE_INFERENCE_ENDPOINT` | Azure AI Foundry 端点 URL | Azure 门户 | | `MISP_URL` | 您的 MISP 实例的基础 URL | 例如 `https://misp.example.com` | | `CORS_ORIGINS` | 逗号分隔的允许来源 | 例如 `https://your-host` | ### 2. 构建并运行 ``` docker compose up --build -d ``` 前端可通过 `https://your-host`(端口 443)访问。端口 80 上的 HTTP 流量会自动重定向到 HTTPS。自签名的 TLS 证书会在首次访问时触发浏览器警告——添加一个浏览器例外以继续访问。 ### 3. 创建首个管理员用户 容器运行后,创建初始管理员账户: ``` docker compose exec backend python -m app.scripts.create_admin ``` 可以通过 UI 中的用户管理页面创建和管理其他用户。 ### 4. 设置您的 MISP API token 每位用户必须配置其个人的 MISP API token,然后才能推送事件: 1. 登录并点击顶部栏中的您的用户名 2. 输入您的 MISP API token 并点击 **Save token** token 在静态存储时已加密,并且绝不会在 API 响应中暴露。推送到 MISP 的事件归属于 token 所有者,从而保持审计追踪的完整性。 ## 开发(不使用 Docker) ### 后端 ``` cd backend python -m venv .venv && source .venv/bin/activate # or .venv\Scripts\activate on Windows pip install -r requirements.txt cp .env.example .env # fill in values uvicorn app.main:app --reload ``` 单独启动 Celery 工作进程: ``` celery -A app.workers.celery_app worker --loglevel=info -Q fetch,extract,misp ``` ### 前端 ``` cd frontend npm install npm run dev ``` ## 添加自定义 LLM 提供商 Karasu 使用了一个抽象层,可以轻松替换不同的 LLM 提供商,而无需触及应用程序的其余部分。 ### 1. 实现基类 在 `backend/app/services/llm/` 中创建一个新文件并实现 `BaseLLMService`: ``` from app.services.llm.base import BaseLLMService from app.services.llm.schemas import LLMRequest, LLMResponse, LLMTokenLimitExceeded class MyLLMService(BaseLLMService): async def extract(self, request: LLMRequest) -> LLMResponse: # Make a single request to your LLM using MISP_EXTRACTION_PROMPT # Raise LLMTokenLimitExceeded if the model hits its output limit # Return an LLMResponse with extracted_data, token counts, and model name ... async def extract_split(self, request: LLMRequest) -> LLMResponse: # Make two parallel requests using MISP_IOC_TTP_PROMPT and MISP_ANALYSIS_PROMPT # Merge the results and return a single LLMResponse ... ``` 提示词定义在 `backend/app/services/llm/prompts.py` 中。提取的 JSON 必须符合流水线其余部分所期望的 schema——请参考现有的 `AzureFoundryLLMService` 实现作为指南。 当模型的输出被截断时,必须引发 `LLMTokenLimitExceeded`(而不是被静默捕获)——这正是触发工作进程中拆分提取回退机制的条件。 ### 2. 在工厂中注册提供商 在 `backend/app/services/llm/factory.py` 中,添加您的提供商: ``` from app.services.llm.my_provider import MyLLMService def get_llm_client() -> BaseLLMService: if settings.LLM_PROVIDER == "azure_foundry": return AzureFoundryLLMService() if settings.LLM_PROVIDER == "my_provider": return MyLLMService() raise ValueError(f"Unsupported LLM provider: {settings.LLM_PROVIDER}") ``` ### 3. 在您的环境中设置提供商 ``` LLM_PROVIDER=my_provider ``` ## 设计决策 ### MISP 发布前的人工审核 LLM 的提取结果不被视为绝对真实。提取完成后,结果会呈现在分析师使用的编辑器中,其中每个字段(IoCs、TTPs、检测规则、威胁狩猎假设)都可以在发送到 MISP 之前进行检查、纠正或删除。推送到 MISP 始终是一个谨慎的手动操作。这让人参与到整个流程中,防止 LLM 的幻觉或错误分类自动污染威胁情报平台。 ### 每用户的 MISP API token 每位分析师使用其自己的个人 API token 而不是共享的服务账户向 MISP 进行身份验证。这保留了 MISP 审计日志中的归属——不同分析师推送的事件会记录在各自的账户下。token 使用 Fernet 对称加密进行静态存储,并且绝不会在 API 响应中暴露。 ### 大型文档的拆分提取 LLM 模型具有有限的输出限制。冗长的文档可能会导致模型在输出 JSON 中途截断其响应,从而产生不可用的输出。为了处理这个问题,Karasu 采用了两次请求的回退策略:首次尝试在一个请求中提取所有内容,输出上限设为 10,000 个 token。如果模型达到此限制,任务会自动将工作拆分为两个并行请求——一个用于 IoCs 和 TTPs,另一个用于检测规则和威胁狩猎假设——每个请求都有自己的 10,000 个 token 上限。因此,每次提取尝试最多可以消耗 30,000 个输出 token。加上针对瞬时故障最多 3 次的重试尝试,单个文档在最坏的情况下可能会消耗多达 120,000 个输出 token。这避免了静默生成不完整的提取结果,而无需分析师重新提交。
标签:AI安全, Chat Copilot, Cloudflare, DLL 劫持, FTP漏洞扫描, IoC提取, IP 地址批量处理, LLM, MITRE ATT&CK, Sigma规则, TTP提取, Unmanaged PE, URL解析, 大语言模型, 威胁分析, 威胁情报自动化, 威胁组织, 安全编排, 实时处理, 情报协同, 情报收集, 指标提取, 搜索引擎查询, 检测规则生成, 测试用例, 漏洞研究, 目标导入, 结构化数据提取, 网络安全, 自动化侦查工具, 自动化平台, 请求拦截, 逆向工具, 隐私保护