React (CVE-2025-55182) - Next(CVE-2025-66478)

12 条回复
96 次浏览

有人中奖吗,说出来让我心里平衡一下。😶

种子用户
OP

存在侥幸心里了(准确的说周五了不想搞了 🙄)
周六电话、信息就过来了 😑

种子用户
OP

@Jimmy 损失没有什么,我容器起的项目。
库,redis 都不在这台服务器上面。
这件事也告诉我,后面搞什么尽量容器化且有问题及时升级 😷

种子用户
OP

⏺ 从一行代码说起

React 里有这么一行代码(处理 Blob 反序列化):

const backingEntry = response._formData.get(blobKey);

正常情况下,response 是 React 内部创建的对象,_formData 是真正的 FormData,.get() 就是读取表单数据。

但如果攻击者能控制 response 这个对象呢?


问题来了:response 从哪来?

往上追溯,response 是从 chunk.reason 里取出来的:

function initializeModelChunk(chunk) {
const { response } = chunk.reason; // response 来自 chunk.reason
// ...
response._formData.get(blobKey); // 然后被使用
}

那 chunk 又从哪来?


继续追溯:chunk 从哪来?

initializeModelChunk 是被 then 方法调用的:

ReactPromise.prototype.then = function(resolve, reject) {
const chunk = this; // chunk 就是 this!

复制
if (chunk.status === 'resolved_model') {
  initializeModelChunk(chunk);
}

}

所以 chunk 就是 this。那 this 是什么?


关键点:this 可以被伪造

JavaScript 有个 thenable 规则:

// 如果对象有 then 方法
const obj = { then: 某个函数 };

// await 它时,JavaScript 会调用
obj.then(resolve, reject);

// 此时函数内部的 this 就是 obj

攻击者的思路:如果我能让 then 指向 ReactPromise.prototype.then,那调用时 this 就是我自己构造的对象!


攻击者怎么拿到 ReactPromise.prototype.then?

React 的反序列化支持 $@ 语法,可以获取内部的 Chunk 对象:

"$@0" → 返回 Chunk 对象(带有 then 方法)

攻击者构造:

{
"then": "$@0", // 指向 Chunk,也就获得了它的 then 方法
}


组装攻击

攻击者发送的数据反序列化后变成:

{
then: Chunk.prototype.then, // 偷来的 then 方法
status: 'resolved_model', // 触发 initializeModelChunk
value: '{"then":"$B0"}', // 让它去读取 Blob
reason: {
response: {
_prefix: "恶意代码字符串",
_formData: { get: Function } // 把 get 换成 Function 构造器!
}
}
}

种子用户
OP

执行流程

  1. React await 这个对象

  2. JavaScript 看到 then 属性,调用 then(),this 指向攻击者的对象

  3. then() 里检查 this.status === 'resolved_model',调用 initializeModelChunk(this)

  4. initializeModelChunk 从 this.reason 取出 response(攻击者伪造的)

  5. 解析 this.value,遇到 "$B0",需要读取 Blob

  6. 调用 response._formData.get(response._prefix + "0")

    Function("恶意代码字符串 0")

    返回一个恶意函数

  7. 恶意函数被执行,RCE 达成


总结

React 以为 response 是自己内部创建的可信对象,从不校验。攻击者通过伪造 this,一路把假的 response
送了进去,最终让 _formData.get() 变成 Function(),实现任意代码执行。

种子用户
OP

@Abc reason: {
response: {
_prefix: "恶意代码//",
_formData: { get: Function } // 直接写 Function
}
}

response._formData.get(response._prefix + '0'); 缩减版

种子用户
OP

@Jimmy 站长,长度被限制了我分了两次发送,这种是不是可以调整一下最大限度。
当然调不调整都可以,毕竟我就发了一次这么长的,哈哈哈哈哈

夜猫
Admin

很少发这么长的 👍,可以发一下你的文章或者 github issue 之类的贴上来可能更好一些。

发表一个评论

R保持