MustafaRajihAli/osint-intelligence-platform

GitHub: MustafaRajihAli/osint-intelligence-platform

自托管 OSINT 调查平台,集成八个数据收集模块、关系图关联、风险评分和离线 AI 分析,支持案件管理与报告导出。

Stars: 0 | Forks: 0

# 🛰️ OSINT 情报平台 **一个自托管的 OSINT 工作台 —— 包含八个收集模块、一个关系图,以及一个可完全离线运行的可插拔 AI 分析师。** [![Python](https://img.shields.io/badge/python-3.12-3776AB)](https://www.python.org/) [![FastAPI](https://img.shields.io/badge/FastAPI-0.115-009688)](https://fastapi.tiangolo.com/) [![Next.js](https://img.shields.io/badge/Next.js-14-000000)](https://nextjs.org/) [![Postgres](https://img.shields.io/badge/Postgres-16-4169E1)](https://www.postgresql.org/) [![Redis](https://img.shields.io/badge/Redis-7-DC382D)](https://redis.io/) [![Docker](https://img.shields.io/badge/docker--compose-one%20command-2496ED)](./docker-compose.yml) [![Findings](https://img.shields.io/badge/findings-Fernet%20encrypted%20at%20rest-b45309)](./backend/app/crypto.py) [![AI](https://img.shields.io/badge/AI-Anthropic%20·%20OpenAI%20·%20Gemini%20·%20Ollama-a855f7)](./backend/app/ai/base.py) [模块](#collection-modules) · [快速开始](#quick-start) · [架构](#how-it-fits-together) · [安全](#security-posture) · [状态](#status)
## 这是什么 一个用于**授权研究和教育**的基于浏览器的调查平台。你注册一个本地账号,对目标运行收集模块,将发现的结果保存到案例中,平台会将该案例关联成一个关系图、一张地图、一个风险表,以及一份由 AI 编写的情报简报 —— 然后将所有内容导出为 JSON 或 PDF。 有两个属性决定了它的所有其他行为: ## 架构组合方式 ``` flowchart TD UI["🖥️ frontend/ Next.js 14
investigate · cases · graph · map · wayback · audit · admin"] UI -->|"JWT REST"| API["api/ FastAPI routers
auth · osint · ai · investigations · audit · admin"] UI <-->|"WebSocket"| API API --> RBAC{{"🔐 auth.py
bcrypt + JWT · require_role()"}} RBAC -->|"role too low"| DENY(["403 — no collection performed"]) RBAC -->|"admin / analyst"| Q Q["arq job queue on Redis"] --> W["tasks.py worker
runs the module off the request thread"] W --> REG["osint/ registry
8 self-registering modules"] REG --> SRC["🌐 public sources
DNS · WHOIS · TLS · crt.sh · platform profiles
GitHub API · ip-api · Wayback · Wikipedia · DDG"] REG -.->|"optional keys"| KEYED["🔑 Shodan · VirusTotal · HIBP · Hunter"] W -->|"progress events"| PS["Redis pub/sub
scan:{job_id}"] PS -->|"live scan feed"| UI W --> RESULT(["finding JSON"]) RESULT --> ENC["🔒 crypto.py EncryptedJSON
Fernet before it touches disk"] ENC --> DB[("🗄️ Postgres
users · investigations · findings · audit_log")] DB --> CORR["graph.py · geo.py · risk.py
correlate · locate · score"] CORR --> OUT["📤 reports.py PDF · JSON export
Cytoscape graph · Leaflet map"] DB --> AI["ai/ provider abstraction
summarize · extract entities · explain diff"] AI --> LLM["🧠 Anthropic · OpenAI · Gemini · Ollama (local)"] API --> AUDIT["📝 audit.py
who ran what, against which target, from which IP"] AUDIT --> DB style RBAC fill:#b45309,stroke:#f59e0b,stroke-width:3px,color:#fff style ENC fill:#14532d,stroke:#22c55e,color:#fff style DENY fill:#7f1d1d,stroke:#ef4444,color:#fff style LLM fill:#1e3a5f,stroke:#3b82f6,color:#fff ``` 扫描绝不是一个阻塞请求。`POST /api/osint/scan/async` 会立即返回一个 `job_id`,worker 将进度发布到 `scan:{job_id}` 频道,浏览器通过 WebSocket 监听该频道 —— 因此,针对 15 个平台的用户名扫描或 `crt.sh` 子域名拉取将以流式传输返回,而不是让请求挂起 30 秒。 ## 收集模块 每个模块都是 `OsintModule` 的子类,并实现一个方法:`async run(target) -> dict`。子类化**即是**注册过程 —— `__init_subclass__` 会将实例放入注册表,并在下次启动时出现在 UI 的下拉菜单中。 | 模块 | 目标 | 收集内容 | 设计说明 | |---|---|---|---| | 👤 **username** | 用户名 | 15 个平台上的存在情况 —— GitHub, Reddit, X, Instagram, TikTok, YouTube, Pinterest, GitLab, HN, Medium, Dev.to, StackOverflow, Keybase, ProductHunt, Twitch | 所有 15 项检查均通过 `asyncio.gather` **并发**运行,因此实际耗时仅为一次请求而非十五次。判定存在需要返回 `200` **且** body 大于 500 字节 —— soft-404 页面通常会返回 200 状态码但附带一个几近空白的页面外壳 | | 📧 **email** | 邮箱地址 | MX 记录、可达性提示、Gravatar URL、HIBP 数据泄露检查 | Gravatar URL 是在本地通过地址的 MD5 加上 `?d=404` 生成的,因此只要命中,就能在没有中间查询服务的情况下证明存在已注册的头像 | | 🌐 **domain** | 域名 | DNS (A/AAAA/MX/NS/TXT/CNAME)、WHOIS、TLS 证书 + SAN、HTTP 头、**来自证书透明度的子域名**、Shodan,以及 Wikipedia/DDG/HackerTarget 丰富化数据 | 七个收集器在一个 `asyncio.gather` 中运行,阻塞式库(`python-whois`、TLS 握手)会被推送到线程执行器中,这样它们就不会阻塞事件循环。子域名来自 **crt.sh** —— CT 日志是权威的且无需密钥,这不同于基于字典的暴力破解 | | 📞 **phone** | E.164 号码 | 有效性、地区、运营商、线路类型、时区、规范格式 | 纯粹使用 `phonenumbers`(Google 的 libphonenumber) —— 离线元数据,无需查询 API,因此受调查的号码绝不会泄露给第三方 | | 🖥️ **ip** | IPv4/IPv6 | 反向 DNS、ASN/ISP/地理位置、Shodan 主机记录、VirusTotal 信誉 | 在报告之前会对地址进行分类(`is_private` / `is_global` / `is_reserved`),因此 RFC1918 结果会被明确标记,而不会作为互联网主机呈现 | | 🔗 **url** | URL | 状态链、最终 URL、标题、Open Graph + Twitter cards、链接、cookies、请求头、**技术指纹**、Wayback 可用性 | 请参阅下文的指纹识别部分 —— 58 个加权特征签名,而不是仅仅读取一下 `Server:` 头 | | 🐙 **github** | 用户名 | 个人资料、组织、仓库、星标/分支、语言 + 主题分布、按 UTC 小时和工作日划分的活动直方图、**在提交元数据中泄露的电子邮件** | 提交邮箱探测是最有趣的部分:`git config user.email` 经常会暴露个人资料中设置为隐私的个人邮箱。它会遍历前 5 个非 fork 仓库,跳过 `noreply.github.com`,并丢弃已经公开的个人资料邮箱,因此保留下来的才是真正的新发现 | | 🖼️ **image** | 图片 URL | 尺寸、格式、SHA-256 + MD5、完整的 EXIF、**以十进制坐标表示的 GPS**、5 个引擎的反向搜索链接 | 反向搜索以**链接而非抓取**的形式提供 —— Google/Yandex/TinEye 的条款禁止自动查询,因此由分析师手动点击进入。服务器端的工作重心放在 EXIF 上,因为 GPS、相机序列号和原始时间戳实际上都存储在这里 |
添加模块 —— 完整的约束条件
``` # backend/app/osint/asn.py from .base import OsintModule class AsnModule(OsintModule): name = "asn" target_type = "asn" async def run(self, target: str) -> dict: return {"target": target, "prefixes": [...]} ``` 在 `backend/app/osint/__init__.py` 中导入它,你就完成了 —— `__init_subclass__` 会注册它,`GET /api/osint/modules` 会报告它,Investigate 下拉菜单会列出它,并且 `POST /scan/async` 可以调度它。 有两个可选的 hook 可以使其成为一等公民: - 来自 `progress.py` 的 `emit("source", site=...)` 会将实时进度流式传输到浏览器。在 job 上下文之外,它是一个 **no-op**,因此同一个模块依然可以在测试或 REPL 中同步运行。 - `risk.py` 中的 scorer 和 `graph.py` 中的 extractor 将该模块纳入风险表和关系图中。这两者都是以模块名称为键的普通字典查找 —— 没有对应条目的模块会被跳过,而绝不会引发崩溃。
技术指纹识别 —— 为什么用 58 个签名而不是读取头部
`Server: nginx` 几乎说明不了任何问题,而且 `X-Powered-By` 经常会被抹除。`fingerprint.py` 会将每个签名与 **五个独立的信号** 进行匹配,并根据每个信号的可伪造程度对其权重进行累积和置信度计算: | 信号 | 权重 | 原因 | |---|---|---| | HTTP header | 40 | 由技术栈本身发出,极少被伪造 | | Cookie name | 35 | `PHPSESSID`, `csrftoken` —— 由框架设置 | | Meta generator | 30 | 由 CMS 写入,有时会被移除 | | Script `src` | 25 | 对于托管的 SDK 信号很强,对于自托管的副本则较弱 | | HTML body | 15 | 最容易被偶然匹配到,因此其价值最低 | ``` tech = fingerprint(html, headers, scripts, meta_tags, cookies) # {"cms": [{"name": "WordPress", "signals": ["html", "meta"], "confidence": 45}], # "language": [{"name": "PHP", "signals": ["implied:WordPress"], "confidence": 50}], ...} ``` 签名声明了 `implies`(例如,WordPress ⇒ PHP,Next.js ⇒ React + Node.js),因此一次匹配就会推导出它所必然依赖的技术栈。未匹配到的 `Server` / `X-Powered-By` 值依然会被原样展示 —— 一个未知的技术栈应该看起来是未知的,而不是被默默丢弃。覆盖范围涵盖 CMS、电子商务、JS 框架、分析工具、标签管理器、支付、CDN、托管、服务器、运行时和安全标头,并且每个模式在导入时仅编译一次。
## 快速开始 ``` git clone https://github.com/MustafaRajihAli/osint-intelligence-platform.git cd osint-intelligence-platform cp .env.example .env # every key in it is optional docker compose up --build ``` | 服务 | URL | |---|---| | App | http://localhost:3000 | | API 文档 (OpenAPI) | http://localhost:8000/docs | | 健康检查 | http://localhost:8000/health | 将启动五个容器:`db`、`redis`、`backend`、`worker`、`frontend`。backend 的入口点会等待 Postgres 接受连接,运行 `alembic upgrade head`,然后启动 uvicorn;worker 设置 `SKIP_MIGRATIONS=1` 并依赖于 backend,因此 **两个容器绝不会竞争同一个迁移**。 **你注册的第一个账号将成为 `admin`** —— 之后注册的所有人都默认为 `analyst`。密码会使用 bcrypt 哈希加密后存入你自己的 Postgres 中;没有外部身份提供商,也不会进行任何外部网络请求。
不使用 Docker 进行本地开发
``` docker compose up db redis # or point DATABASE_URL / REDIS_URL at your own ``` ``` cd backend python -m venv .venv && source .venv/bin/activate # Windows: .venv\Scripts\activate pip install -r requirements.txt alembic upgrade head uvicorn app.main:app --reload arq app.tasks.WorkerSettings # separate shell — async scans need the worker ``` ``` cd frontend npm install npm run dev ``` `app.main` 仅为 `http://localhost:3000` 挂载了 CORS。如果要从其他源为前端提供服务,则意味着需要修改 `backend/app/main.py` 中的 `allow_origins`。
使用 Ollama 完全离线运行 AI 层
``` ollama pull llama3.2 ``` Ollama 监听 `localhost:11434`;backend 通过 `OLLAMA_BASE_URL` 连接它,该变量默认为 `http://host.docker.internal:11434` —— 这适用于 Windows/macOS 上的 Docker Desktop。在 Linux 上,请使用宿主机 IP 或者在同级容器中运行 Ollama。在 **Settings** 中选择 `OLLAMA`;模型下拉列表会通过 `/api/tags` 实时填充,因此你可以从实际已拉取的模型中进行选择。 请求一个尚未拉取的模型会返回已安装列表以及确切的命令,而不是一个简单的 404: ``` Ollama model 'llama3.1' is not pulled. Installed models on host: llama3.2:latest. Either set the model in Settings to one of these, or run `ollama pull llama3.1` on the host. ``` 在 Settings 中切换提供商**会重置模型名称** —— 否则 `gpt-4o-mini` 会被发送给 Ollama 并以 404 失败,看起来就像是安装损坏了一样。
## 从目标到情报简报 ``` Investigate → pick module → RUN SCAN ──► live source-by-source feed └──► finding JSON + risk score │ save to case ───┤ ▼ Cases → case detail ──► risk table · AI entity extraction · JSON / PDF export ├──► /graph relationship graph (Cytoscape, cose-bilkent layout) └──► /map geolocated findings (Leaflet) ``` ### 1 — 关联是核心 单个发现只是一次查询;而一个案例是一项调查。`graph.py` 会通过每个模块特定的 extractor 遍历每个发现结果,发出 `(kind, value, label)` 实体,并 **在 `kind:value` 上进行去重** —— 因此,在邮箱发现中作为 MX 主机出现的域名、在域名发现中作为 TLS SAN 出现的域名,以及在 URL 发现中作为链接目标出现的域名,会塌缩成 **一个带有三条边的节点**。这种聚合正是单个扫描无法向你展示的发现。 节点类型是带有类型和颜色编码的:`domain`、`subdomain`、`host`、`ip`、`asn`、`email`、`profile`、`repo`、`org`、`place`、`country`、`breach`、`tech`、`hash`。每条边都携带着生成它的模块,因此每次推断都能保持归属于某次扫描。 ### 2 — 地图通过交叉引用填补空白 `geo.py` 根据地理位置查询结果放置 IP 发现,并根据 **EXIF GPS** 放置图片发现。域名本身没有坐标 —— 因此它会索引已定位的 IP,将它们与每个域名的 A/AAAA 记录进行匹配,并将域名放置在其解析出的宿主机上,标记为 `Resolves to 93.184.216.34 — …`。任何无法放置的内容都会被返回到 `unresolved` 中而不是被丢弃,因为缺失的图钉应当以缺失的状态被看见。 ### 3 — 风险评分,以一种启发式算法呈现 ``` score_finding("domain", data) # {"score": 70, "level": "high", # "reasons": ["TLS 证书 12 天前已过期", # "庞大的攻击面:通过 CT logs 发现 284 个子域名"]} ``` 七个评分器,每个模块一个,每个都返回 **分数加上人类可读的原因** —— 绝不只是一个单纯的数字。阈值范围:`<30` 低风险,`30–59` 中风险,`≥60` 高风险。过期的 TLS 记 50 分,HIBP 数据泄露次数越多分数越高,VirusTotal 检出率随扫描引擎数量增加而增涨,注册不到一年的域名加 20 分,缺失 HSTS/CSP 加 10 分。 ### 4 — AI 是分析师,而不是神谕 三种提示词,四种可互换的提供商: | Endpoint | 产出 | 提示词原则 | |---|---|---| | `POST /api/ai/summarize` | 针对单个发现的 Markdown 情报简报 | *“实事求是,避免猜测”* —— 关键事实、风险指标、建议的后续线索 | | `POST /api/ai/extract` | 带有置信度和来源的类型实体 | 严格的 JSON 契约;防御性地剥离代码块标记,无法解析的输出将返回 `entities: []` **外加原始文本**,这样错误的响应将是可见的,而不是静默的空值 | | `POST /api/ai/explain-diff` | 两个 Wayback 快照之间发生实质性变化的内容 | 明确告知其忽略导航和样板文件的变动,报告声明、姓名、联系方式、价格、被删除的披露信息以及语气的变化 | 提供商是在 **`get_provider()` 内部延迟导入**的 —— 一个提供商的 SDK 缺失或损坏不能阻止其他三个正常工作,并且缺少密钥会在构造时抛出异常,指明需要设置的 env var。 ### 5 — Wayback 差异比对 给出一个 URL 和两个日期。平台会解析出每个日期最接近的快照,剥离两者中的脚本、样式和 Wayback 工具栏注入,并生成统一的文本差异 —— 新增的行、删除的行、计数。然后 `explain-diff` 会替你阅读它。这对于终结许多调查的那个问题非常有用:*在他们修改之前,这个页面上写的是什么?* ## 安全态势 这是一个调查工具,因此它保存着工作流中最敏感的工件:你搜索了什么以及返回了什么。 | 控制 | 实现 | |---|---| | **发现数据静态加密** | `EncryptedJSON`,一个 SQLAlchemy `TypeDecorator`,在绑定时对每个发现的 payload 进行 Fernet 加密,并在加载时解密。应用层永远不会看到密文;数据库永远不会看到明文 | | **密钥处理** | 如果设置了 `ENCRYPTION_KEY`(一个真正的 Fernet 密钥)则使用它,否则通过 20 万次迭代的 PBKDF2-HMAC-SHA256 从 `JWT_SECRET` 派生 —— 兼顾了开发便利性,且没有不加密的回退路径 | | **安全上线** | 加密的行被标记为 `{"_enc": "v1", "ct": …}`;任何未标记的行都将原样返回,因此启用加密不会使现有的发现数据孤立。无法解密的行会返回 `{"_decryption_error": true}` 而不是引发异常 | | **RBAC** | 数字角色阶梯 —— `admin` 3, `analyst` 2, `viewer` 1 —— 由 `require_role()` 作为依赖项强制执行。收集和案例变更操作需要 `analyst` 角色;viewer 可以阅读案例但无法运行扫描 | | **最后管理员保护** | 拒绝降级最后一个 `admin`,因为没有 admin 的实例无法将任何人重新提升为 admin | | **审计跟踪** | 注册、登录、**登录失败**、扫描(模块 + 目标 + job id)、案例创建/删除、发现结果添加以及角色变更 —— 每一项都包含操作者、IP(感知 `X-Forwarded-For`)和 user agent。审计写入操作经过了封装,因此日志记录失败绝不会破坏其描述的请求 | | **审计作用域** | `scope=all` **仅** 对管理员有效;所有其他调用者都会被静默强制回退到 `own`,因此该参数无法被篡改以导致信息泄露 | | **WebSocket 认证** | Socket 先接受连接,然后要求在 5 秒内将 JWT 作为第一条消息发送,否则将以 `4401` 关闭 —— 浏览器无法在 WebSocket 握手时设置 header,因此 token 无法通过常规方式传输 | | **PDF 下载认证** | 接受 `Authorization: Bearer` **或** `?token=`,因为 `window.open` 无法附加 header。查询字符串路径会进行相同的验证,并且像每个案例路由一样,其作用域被限制在 `owner_id` | | **密码处理** | 通过 passlib 使用 bcrypt,并防御性地截断至 bcrypt 的 72 字节输入限制,这样长的口令短语会安全失败,而不是引发异常 | ## 合法与合规使用 ## 项目结构 ``` backend/ ├── app/ │ ├── main.py FastAPI app, CORS, router mounting │ ├── config.py pydantic-settings — every secret is optional │ ├── db.py async SQLAlchemy engine + session dependency │ ├── models.py User · Investigation · Finding · AuditLog │ ├── auth.py bcrypt, JWT, role ladder, require_role() │ ├── crypto.py EncryptedJSON TypeDecorator (Fernet) │ ├── audit.py audit writer — never breaks its caller │ ├── progress.py contextvar job context → Redis pub/sub │ ├── tasks.py arq worker: scan_task + WorkerSettings │ ├── risk.py 7 per-module scorers with stated reasons │ ├── graph.py findings → deduplicated entity graph │ ├── geo.py geolocatable points + domain↔IP cross-reference │ ├── reports.py ReportLab PDF with risk summary + raw data │ ├── enrichment.py Wikipedia · DuckDuckGo · HackerTarget (keyless) │ ├── wayback.py snapshot resolve, text extraction, unified diff │ ├── api/ auth · osint · ai · investigations · audit · admin │ ├── osint/ 8 self-registering modules + 58-signature fingerprinter │ └── ai/ provider abstraction + 4 implementations ├── alembic/versions/ 0001_initial · 0002_audit_log ├── entrypoint.sh wait for Postgres → migrate → exec └── Dockerfile frontend/ ├── app/ │ ├── page.tsx register / login console │ ├── investigate/ module picker, live scan feed, AI summary, save to case │ ├── cases/ list · detail (risk + entities + export) · graph · map │ ├── wayback/ snapshot diff + AI explanation │ ├── audit/ activity log (own, or global for admins) │ ├── admin/ user list + role management │ └── settings/ AI provider + model selection ├── components/Nav.tsx role-aware navigation ├── lib/ api client · zustand settings store · useCurrentUser └── tailwind.config.ts dark "cyber" palette docker-compose.yml db · redis · backend · worker · frontend ``` ### 数据库迁移 Schema 由 **Alembic** 管理,并在每次 backend 启动时应用。在修改了 `models.py` 之后: ``` docker compose exec backend alembic revision --autogenerate -m "add column" docker compose exec backend alembic upgrade head docker compose exec backend alembic downgrade -1 # rollback ``` `0001_initial` 创建 `users`、`investigations`、`findings`;`0002_audit_log` 添加 `audit_log`。 ## 状态 | 领域 | 状态 | |---|---| | 认证、RBAC、审计日志 | ✅ 完成 —— bcrypt + JWT、三种角色、最后管理员保护、受限的审计读取 | | 发现数据静态加密 | ✅ 完成 —— Fernet 列加密,具有向后兼容的明文读取路径 | | 收集模块 | ✅ 8 个已上线;依赖密钥的集成在密钥未设置时会优雅降级 | | 技术指纹识别 | ✅ 11 个类别下的 58 个加权签名,带有 `implies` 推导 | | 异步扫描 + 实时进度 | ✅ arq worker、Redis pub/sub、经过认证的 WebSocket 数据流 | | 关联:图 · 地图 · 风险 | ✅ 对于所有 8 个模块均已完成 —— 图片没有风险评分器,因为其中没有任何具有评分意义的内容 | | 导出:JSON · PDF | ✅ 完成 —— PDF 包含风险摘要、原因和原始数据 | | AI:summarize · extract · explain-diff | ✅ 在 4 种提供商上均完成,采用延迟导入 | | Wayback 差异比对 | 🟨 可用 —— 快照解析、剥离工具栏的文本差异、AI 解释;差异被截断(双向各 300 行,统一块 1500 行) | | 实时多分析师案例视图 | 🟨 可用 —— 案例 socket 推送 finding-added 事件并且客户端重新获取数据;没有状态呈现、cursor 或冲突处理 | | 自动化测试 | ❌ 尚未完成。最有价值的首个测试目标是 `fingerprint()`、`risk.score_finding()`、`graph.build_graph()` 和 `geo.build_geo()` —— 它们都是基于字典的纯函数,无需网络和数据库即可测试 | | CI | ❌ 尚未完成 | | 生产级镜像 | ❌ 两个 Dockerfile 均处于开发模式(`--reload`、`npm run dev`),且源代码以绑定挂载方式载入 | | 速率限制 / 配额 | ❌ 没有任何机制限制用户。`crt.sh`、`ip-api`(约 45 次请求/分钟)和 HackerTarget(约 50 次请求/天)会在本平台之前率先对你进行速率限制 | **在你相信结果之前值得了解的已知限制。** 用户名是否存在只是一种启发式判断 —— 存在 soft-404、地理封锁或机器人拦截的平台会被判定为不存在,而激进的插页式广告可能会被判定为存在,因此请将命中视为线索而非确凿证据。WHOIS 输出因注册商而异,并以字符串形式直接透传,未作规范化处理。反向图片搜索设计上仅提供链接。而且 `summarize` / `explain-diff` 会将发现的数据发送到你选择的任何提供商 —— 如果这很重要,请选择 Ollama,因为它是唯一一个不会将任何数据发出宿主机的提供商。 **路线图,按实际产生价值的顺序排列:** 针对纯相关函数的测试套件,接着是生产级 Dockerfiles 和 CI,然后是基于用户的速率限制,再是更多模块(ASN、CVE 查找、粘贴站点、`archive.today`),然后是在关系图旁边的案例时间线视图,最后是基于用户的加密密钥存储,从而让提供商密钥完全离开 `.env`。
专为经过授权的 OSINT 研究和教育而构建。请按此初衷合理使用。
标签:AI风险缓解, AV绕过, ESC4, FastAPI, LLM评估, Ollama, OSINT, 动态调用, 实时处理, 情报收集, 搜索引擎查询, 本地部署, 测试用例, 漏洞研究, 请求拦截, 逆向工具