Jinish2170/BenardAI

GitHub: Jinish2170/BenardAI

自托管 AI 威胁分诊平台,通过确定性静态分析与威胁情报聚合为 LLM 提供可审计证据,生成附带引用溯源的安全判定结论。

Stars: 0 | Forks: 0

# Bernard ### 自托管 AI 威胁分诊工作站 **拖入文件。粘贴 URL。获取附带证据溯源的判定结果。** [![License: MIT](https://img.shields.io/badge/License-MIT-22c55e.svg?style=flat-square)](LICENSE) [![Version](https://img.shields.io/badge/version-2.0.0-06b6d4?style=flat-square)](https://github.com/Jinish2170/BenardAI/releases) [![Python](https://img.shields.io/badge/Python-3.11+-3776AB?style=flat-square&logo=python&logoColor=white)](https://www.python.org) [![FastAPI](https://img.shields.io/badge/FastAPI-0.115+-009688?style=flat-square&logo=fastapi&logoColor=white)](https://fastapi.tiangolo.com) [![React](https://img.shields.io/badge/React-18-61dafb?style=flat-square&logo=react&logoColor=black)](https://react.dev) [![NVIDIA NIM](https://img.shields.io/badge/LLM-NVIDIA%20NIM-76b900?style=flat-square&logo=nvidia&logoColor=white)](https://build.nvidia.com) [![MITRE ATT&CK](https://img.shields.io/badge/MITRE-ATT%26CK%20mapped-c0392b?style=flat-square)](https://attack.mitre.org/) [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-ff69b4?style=flat-square)](#contributing) [**快速开始**](#-quick-start) · [**工作原理**](#-how-it-works) · [**API**](#-api) · [**架构**](#-architecture) · [**路线图**](#-roadmap)
## 概述 **Bernard** 是一个自托管的威胁分诊工作站,其构建基于一个简单原则:**确定性分析器首先收集证据,然后由 LLM 综合出必须引用该证据的判定结论。** 没有黑盒评分,没有捏造的 CVE 编号,也没有孤立的 MITRE 技术断言。 交给它一个文件、URL、IP、域名或 hash。Bernard 会运行静态分析(使用 LIEF 分析 PE,oletools 分析 Office,pdfid 分析 PDF,YARA-X 配合 YARA-Forge 规则),结合威胁情报(VirusTotal, abuse.ch URLhaus / ThreatFox / MalwareBazaar, AbuseIPDB)进行丰富,并让 LLM(默认为 NVIDIA NIM Llama 3.3 70B)给出判定 —— 严格锚定引用、MITRE ATT&CK 映射,并在证据不充分时明确弃权。 ``` VirusTotal → multi-engine verdict, no reasoning, paid for serious use Joe Sandbox → deep behavioral analysis, $$$$, requires a sample upload to a 3rd party Cuckoo / CAPE → great sandboxing, heavy infra, no verdict synthesis Bernard → static + intel + LLM synthesis with auditable citations, on your machine, free ``` ## 📸 仪表盘
Bernard threat triage dashboard *对 Windows PE 的实时分析。悬浮的毛玻璃顶栏显示了配置的 LLM 模型 + 各情报提供商(VT · AbuseIPDB · abuse.ch · MITRE)的颜色编码状态标签。支持拖放的文件区域,大尺寸的语义判定徽章(根据分类显示头骨 / 警告 / 对勾 / 帮助图标),元信息胶囊(严重性 · 置信度 · 时间 · 模型 · 证据数),如 `[pe.suspicious_imports]` 的引用胶囊可以直接映射回实际证据行,以及当 LLM 正确拒绝猜测时显示的“为什么 Bernard 弃权”部分。*
### 在 UI 中你可以做什么 | | | |---|---| | 🎯 **拖放文件区** | 拖入任何 artifact(PE、PDF、Office、脚本等)或点击选择。实时文件胶囊预览。 | | 🔤 **智能文本输入** | 粘贴 URL、IP、域名或 hash —— Bernard 会自动检测类型。 | | 🎨 **判定主卡片** | 大尺寸徽章,带有分类图标、根据严重性着色的渐变效果、摘要,以及用于快速浏览的元信息胶囊条 | | 🔗 **引用胶囊** | 关键指标中的每个 `[analyzer.field]` token 都会渲染为带有提示框的胶囊 —— 点击可跳转至对应的证据行 | | 📂 **按分析器分组的证据** | 可折叠的分组卡片(pe / pdf / yara / virustotal / …),每组均带有最高严重性徽章 | | 🛰 **MITRE 标签 → 详情卡** | 点击任意技术标签,Bernard 会按需获取官方 ATT&CK 描述、战术标签以及 `attack.mitre.org` 链接 | | 📡 **流式进度** | 每个 pipeline 阶段(搜索 → 分析 → 丰富 → 分诊)通过 NDJSON 实时流式传输;最新阶段带有脉冲效果 | | 🗂 **历史记录标签页** | 过往分析会持久化存储到磁盘,点击任意行即可重新打开完整记录 | | ⬇ **导出 JSON** | 一键下载完整记录(证据 + 判定 + 统计数据),用于离线审查或 pipeline 摄取 | | ✨ **体验优化** | 悬浮毛玻璃顶栏,引用使用 JetBrains Mono 字体,淡入动画,响应式 `<720px` 布局 | ## ✨ 功能说明 | | | |---|---| | 📦 **PE 静态分析** | LIEF 解析头、节区、导入表、签名、overlay;标记可疑的 API 组合(进程注入、反调试、持久化)和高熵值节区(加壳) | | 📑 **PDF 分析** | pdfid 风格的关键字计数(`/JS`, `/JavaScript`, `/OpenAction`, `/Launch`, `/EmbeddedFile`);投递启发式算法会标记包含活动内容的短小 PDF | | 📄 **Office 宏分析** | oletools (`olevba`) 提取宏,运行 AutoExec/Suspicious 关键字扫描器,从 VBA 中提取 IOC | | 🔬 **通用文件特征** | SHA-256/SHA-1/MD5,Shannon 熵,可打印字符串,提取嵌入的 URL/IP,可疑 token 启发式扫描 | | 🐝 **YARA-X 扫描** | 全新的 Rust 重写版 YARA(2026 稳定版),搭载自动初始化的 [YARA-Forge](https://yarahq.github.io/) 精选规则 | | 🌐 **威胁情报丰富** | VirusTotal(hash / URL / IP),abuse.ch URLhaus + ThreatFox + MalwareBazaar,AbuseIPDB —— 在缺少 API 密钥时均支持优雅降级 | | 🎯 **MITRE ATT&CK 映射** | LLM 将证据映射到 ATT&CK 技术;针对官方 STIX bundle 进行后验证,孤立/捏造的技术 ID 将被丢弃 | | 🛡 **引用锚定** | 每个关键指标和每个 MITRE 技术都会引用具体的 `[analyzer.field]` 证据作为支撑 —— 捏造的引用会被拒绝 | | 🤔 **宁弃权不幻觉** | 如果证据稀少或相互矛盾,判定结果将为 `inconclusive` 并附带明确理由 —— 而不是一个自信的错误答案 | | 🧪 **提示注入防御** | 分析器输出在到达 LLM 之前,会经过 regex 过滤净化(去除控制字符,屏蔽 `ignore previous instructions` 模式) | | 💾 **调查历史** | 每次分析都会持久化到 `analyses/YYYY-MM-DD/` —— 包含完整证据 + 判定,可导出为 JSON | | 🖥 **Web 仪表盘** | React + Vite UI,包含判定卡片、证据审计表、MITRE 标签、基于 NDJSON 的流式进度、历史记录标签页、导出功能 | | 🔌 **REST + 流式 API** | FastAPI 提供 `/analyze`, `/analyze/stream` (NDJSON), `/analyses`, `/analysis/{id}` | | ⌨ **CLI** | `bernard scan --file sample.exe` 或 `bernard scan --value http://...` | ## 🚀 快速开始 ### 前置条件 - **Python 3.11+**(LIEF + yara-x 需要 native wheels) - **Node.js 20+**(用于运行仪表盘) - **NVIDIA NIM API key**(可在 [build.nvidia.com](https://build.nvidia.com/) 免费获取)—— 或任何兼容 OpenAI 的提供商 ### 安装 ``` git clone https://github.com/Jinish2170/BenardAI.git cd BenardAI # Backend pip install -e . # 引导 MITRE ATT&CK catalog + YARA-Forge rules(一次性,总计约 55 MB) python scripts/bootstrap_mitre.py python scripts/bootstrap_yara.py # Frontend cd frontend && npm install && cd .. # 配置你的 LLM key cp .env.example .env # → 编辑 .env:将 NVIDIA NIM key 粘贴到 LLM_API_KEY # 可选:VT_API_KEY, ABUSEIPDB_API_KEY, ABUSECH_API_KEY ``` ### 运行 ``` # API 在 :3003 且 dashboard 在 :3000(推荐) bernard serve & cd frontend && npm run dev ``` 然后打开 **http://localhost:3000**,拖入文件或粘贴 URL/IP/域名/hash。 ### CLI ``` bernard scan --file ./samples/suspicious.exe bernard scan --value "https://example.com/payload.bin" bernard scan --value "8.8.8.8" bernard scan --value "275a021bbfb6489e54d471899f7db9d1663fc695ec2fe2a2c4538aabf651fd0f" bernard scan --file sample.docm --json # raw JSON for piping ``` ## ⚙ 配置 `.env` 设置(参见 `.env.example`): | 变量 | 默认值 | 用途 | |----------|---------|---------| | `LLM_API_KEY` | *(参见下方的自动发现)* | LLM 提供商的 API key | | `LLM_BASE_URL` | `https://integrate.api.nvidia.com/v1` | OpenAI 兼容的 endpoint | | `LLM_MODEL` | `meta/llama-3.3-70b-instruct` | 该 endpoint 的模型 ID | | `VT_API_KEY` | *(可选)* | 启用 VirusTotal hash/URL/IP 查询(免费层级:4 次请求/分钟) | | `ABUSEIPDB_API_KEY` | *(可选)* | 启用 AbuseIPDB IP 信誉查询(免费:1000 次请求/天) | | `ABUSECH_API_KEY` | *(可选)* | 启用 URLhaus, ThreatFox, MalwareBazaar(可在 [auth.abuse.ch](https://auth.abuse.ch/) 免费获取) | | `CCNIM_ENV` | *(可选)* | 覆盖 cc-nim 环境变量的自动发现路径 | | `PORT` | `3003` | API 服务器端口 | | `MAX_UPLOAD_MB` | `100` | 单次上传大小上限 | | `ANALYSIS_TIMEOUT_S` | `120` | 单次分析硬超时时间 | ### 🔑 NVIDIA NIM key 自动发现 如果 `LLM_API_KEY` 为空,Bernard 会自动从你中央的 [cc-nim](https://github.com/cc-nim/cc-nim) `.env` 文件中的 `NVIDIA_NIM_API_KEY` 解析。默认查找顺序: 1. `$CCNIM_ENV`(显式覆盖) 2. `~/cc-nim/.env` 这意味着你可以为 NVIDIA NIM key 保留唯一的真实来源,Bernard 会自动获取它,无需到处复制。在 `.env` 中设置 `LLM_API_KEY` 即可进行覆盖。 ### 备选 LLM 提供商 任何兼容 OpenAI 的 endpoint 均可运行: ``` # OpenRouter LLM_BASE_URL=https://openrouter.ai/api/v1 LLM_MODEL=meta-llama/llama-3.3-70b-instruct:free # Groq LLM_BASE_URL=https://api.groq.com/openai/v1 LLM_MODEL=llama-3.3-70b-versatile # 本地 Ollama LLM_BASE_URL=http://localhost:11434/v1 LLM_MODEL=llama3.3 LLM_API_KEY=ollama ``` ## 🔬 工作原理 ``` ┌──────────────────────────────────────────────────────────┐ │ BERNARD PIPELINE │ └──────────────────────────────────────────────────────────┘ input ──┬─→ file ──→ [PE] [PDF] [Office] [Generic] [YARA-X] ─┐ │ │ ├─→ url ───────────────────────────────────────────────────────────── │ ├─→ ip ───────────────────────────────────────────────────────────── ├─→ Evidence[] ├─→ domain ─────────────────────────────────────────────────────────── │ └─→ hash ───────────────────────────────────────────────────────────── │ │ ┌───────────────────────────────────────────────────┘ ↓ [Threat-intel enrichment] VirusTotal · URLhaus · ThreatFox · MalwareBazaar · AbuseIPDB ↓ [Sanitize for LLM] ← redact control chars, ↓ prompt-injection patterns [NVIDIA NIM Llama 3.3 70B] ↓ [Post-validate JSON] ← reject orphan citations ↓ reject unknown MITRE IDs Verdict (classification + severity + cited indicators + grounded MITRE techniques + actions) ``` ### 设计原则 | 原则 | 实践 | |-----------|----------| | **证据优先,LLM 其后** | LLM 永远不会看到样本的原始字节 —— 只能看到由确定性分析器生成的结构化 `Evidence`。这就是防止产生捏造事实的引用契约。 | | **强制引用** | 每个 `key_indicator` 必须以 `[analyzer.field]` 结尾。在实际证据中不存在的引用会在验证期间被丢弃。 | | **验证 MITRE ID** | LLM 声称的技术 ID 会与官方 ATT&CK STIX bundle 进行核对。未知的 ID 会被拒绝,不予显示。 | | **宁弃权不幻觉** | 当证据稀少时,系统提示词会强制要求 `classification: inconclusive` —— 并且 LLM 必须解释*原因*。 | | **削弱提示注入** | 所有字符串字段在到达 LLM 之前,都会经过 regex 过滤(去除控制字符 + 屏蔽已知的注入模式)。 | | **严格的 JSON 输出** | `response_format: json_object` 强制要求 schema。如果 LLM 输出了无效的 JSON,解析器将直接拒绝。 | 这些规则被同时内嵌在系统提示词(`src/bernard/triage/prompts.py`)和后验证器(`src/bernard/triage/engine.py`)中。 ## 📡 API | 方法 | 路径 | 用途 | |--------|------|---------| | `GET` | `/health` | 存活状态 + 模型 + 标志位:`llm_configured` · `vt_configured` · `abuseipdb_configured` · `abusech_configured` · `mitre_loaded`(为仪表盘的状态标签提供支持) | | `POST` | `/analyze` | Multipart `file=` 或表单 `value=...`(url/ip/domain/hash)。返回完整记录。 | | `POST` | `/analyze/stream` | 同样的载荷,以 NDJSON 流式传输进度(`{event: "progress", data: {...}}`),最后附带 `{event: "result", data: AnalysisRecord}` | | `GET` | `/analyses?limit=50` | 列出过往分析(最新在前) | | `GET` | `/analysis/{id}` | 加载完整的历史记录 | | `GET` | `/technique/{technique_id}` | MITRE ATT&CK 技术元数据(名称 · 描述 · 战术 · `attack.mitre.org` URL)—— 供仪表盘按需渲染技术详情卡片使用 | ### 示例 ``` curl -X POST http://localhost:3003/analyze \ -F "file=@./suspect.exe" curl -X POST http://localhost:3003/analyze \ -F "value=https://example.com/payload" ``` ### 判定结构(节选) ``` { "id": "ana-...", "input": { "kind": "file", "filename": "suspect.exe", "file_sha256": "..." }, "evidence": [ /* Evidence[]: analyzer + field + value + severity + description */ ], "verdict": { "classification": "malicious", // benign | suspicious | malicious | inconclusive "severity": "high", // info | low | medium | high | critical "confidence": "high", "summary": "Sample is a packed Windows PE with extensive process-injection imports and a MalwareBazaar match...", "key_indicators": [ "PE imports VirtualAllocEx + WriteProcessMemory + CreateRemoteThread — classic process-injection chain [pe.suspicious_imports]", "MalwareBazaar identifies this hash as AgentTesla [malwarebazaar.match]", "VirusTotal: 47/72 engines flag as malicious [virustotal.detection_ratio]" ], "mitre_techniques": [ { "technique_id": "T1055", "name": "Process Injection", "rationale": "Imports VirtualAllocEx/WriteProcessMemory/CreateRemoteThread together — textbook process-hollowing primitive.", "cites": ["pe.suspicious_imports"] } ], "recommended_actions": ["Isolate host, capture memory, hunt for child process spawning"] }, "stats": { "duration_ms": 24102, "evidence_count": 31, "llm_model": "meta/llama-3.3-70b-instruct" } } ``` ## 🏗 架构 ``` BenardAI/ ├── src/bernard/ │ ├── analyzers/ │ │ ├── base.py FileAnalyzer/StringAnalyzer ABCs + safe-string sanitizer │ │ ├── file/ │ │ │ ├── pe.py LIEF: headers, imports, sections, signing, entropy │ │ │ ├── pdf.py PDFiD-style keyword counts + dropper heuristic │ │ │ ├── office.py oletools (olevba): VBA macros + IOC extraction │ │ │ └── generic.py hashes, entropy, strings, embedded URL/IP │ │ └── yara_engine.py YARA-X scanner over YARA-Forge ruleset │ ├── intel/ │ │ ├── vt.py VirusTotal (vt-py): file / URL / IP │ │ ├── urlhaus.py abuse.ch URLhaus │ │ ├── threatfox.py abuse.ch ThreatFox (IOC search) │ │ ├── bazaar.py abuse.ch MalwareBazaar (hash → family) │ │ ├── abuseipdb.py AbuseIPDB IP reputation │ │ └── mitre.py STIX-backed MITRE ATT&CK catalog (validator) │ ├── triage/ │ │ ├── llm.py OpenAI-compatible client (NVIDIA NIM by default) │ │ ├── prompts.py System + user prompts; JSON schema; citation rules │ │ └── engine.py Run + parse + post-validate (drop orphan citations, unknown MITRE IDs) │ ├── orchestrator.py Routes input → analyzers → intel → triage → record │ ├── store.py File-based AnalysisStore (analyses/YYYY-MM-DD/) │ ├── api/server.py FastAPI: REST + NDJSON streaming │ ├── cli.py `bernard serve` and `bernard scan` │ ├── config.py Env-driven config (LLM, intel keys, server, storage) │ └── types.py Pydantic models (Evidence, Verdict, AnalysisRecord, …) │ ├── frontend/ React + Vite dashboard (cyan/navy theme) │ └── src/App.tsx Verdict card · Evidence · MITRE · History │ ├── scripts/ │ ├── bootstrap_mitre.py Download enterprise-attack STIX │ └── bootstrap_yara.py Download YARA-Forge core ruleset │ ├── rules/yara-forge/ YARA rules (gitignored, regenerable) ├── data/mitre-attack-stix/ ATT&CK STIX bundle (gitignored, regenerable) ├── analyses/ Persisted analyses (gitignored) └── uploads/ Server-side upload staging (gitignored) ``` ## 🛠 命令 | 命令 | 用途 | |---------|---------| | `bernard serve` | 在 `$PORT`(默认为 3003)上启动 FastAPI 服务器 | | `bern scan --file ` | 无头模式文件扫描;使用 `--json` 输出原始 JSON | | `bernard scan --value ` | 无头模式 IOC 扫描 | | `python scripts/bootstrap_mitre.py` | (重新)下载 MITRE STIX bundle | | `python scripts/bootstrap_yara.py` | (重新)下载 YARA-Forge 核心规则集 | | `cd frontend && npm run dev` | 在 `:3000` 启动仪表盘开发服务器(将 `/api` 代理至 `:3003`) | | `cd frontend && npm run build` | 构建生产环境的仪表盘 bundle | ## 🆚 对比 | | Bernard | VirusTotal | Joe Sandbox | Cuckoo / CAPE | 人工分诊 | |---|:---:|:---:|:---:|:---:|:---:| | 带引用的判定(每个断言 → 证据) | ✅ | ❌ | ⚠️ | ❌ | ✅ | | MITRE ATT&CK 映射(经验证) | ✅ | ⚠️ | ✅ | ⚠️ | ✅ | | 免费 / 自托管 | ✅ | ⚠️ | ❌ | ✅ | — | | 开源 | ✅ | ❌ | ❌ | ✅ | — | | 带弃权机制的 LLM 综合 | ✅ | ❌ | ⚠️ | ❌ | — | | YARA-X(2026 Rust 版 YARA) | ✅ | ✅ | ⚠️ | ⚠️ | — | | 样本不上传给第三方 | ✅ | ❌ | ❌ | ✅ | ✅ | | 5 分钟内完成设置 | ✅ | ✅ | ❌ | ❌ | — | Bernard **不是**沙盒 —— 它不进行动态执行。它与沙盒(CAPE / Drakvuf)完美搭配,通过摄取它们的报告作为额外的证据源(阶段 2)。 ## 🗺 路线图 - [x] **v2.0** —— 确定性分析器 + 威胁情报丰富 + 带有引用锚定 + MITRE 验证 + 仪表盘 + 持久化的 LLM 分诊 - [ ] **v2.1** —— 沙盒集成:摄取 CAPE / Drakvuf 报告作为证据 - [ ] **v2.2** —— 带自我一致性的多轮 LLM(3 条推理路径,对分类进行投票) - [ ] **v2.3** —— Email/EML 分诊(提取附件 + 链接,运行完整 pipeline) - [ ] **v2.4** —— 从确认的恶意集群中自动生成 Sigma + YARA 规则 - [ ] **v2.5** —— 用于监控观察列表命中的 Webhook + Slack/Teams 通知器 - [ ] **v3.0** —— 多用户 / RBAC / 审计日志;可作为组织级设备进行部署 ## ⚠ 法律与道德 Bernard 专为**授权的防御性安全、事件响应、威胁研究和教育**而构建。 - 仅分析你有权分析的样本 - 遵守 API 速率限制(Bernard 会限制并发的情报请求) - 带引用的判定对人类分析师来说是*辅助*,而非替代品 —— 请通过主要来源验证关键发现 - 这*不是*沙盒;样本不会被执行 ## 📄 许可证 MIT © [Jinish Dhola](https://github.com/Jinish2170)
**使用 Python · FastAPI · LIEF · YARA-X · NVIDIA NIM · React 构建。** [⭐ 在 GitHub 上 Star](https://github.com/Jinish2170/BenardAI) · [🐛 报告问题](https://github.com/Jinish2170/BenardAI/issues)
标签:AI安全分析, AV绕过, DAST, DNS 反向解析, FastAPI, Go语言工具, LangChain, Python, 威胁情报, 开发者工具, 恶意软件分析, 搜索语句(dork), 无后门, 网络信息收集, 网络测绘, 自动化分类, 轻量级, 逆向工具