1. 개요
2025년 12월 03일 React 팀은 React Sever Component에 인증되지 않은
원격 코드 실행 취약점이 있다고 발표 하였다.
[그림 1] React Team Official Blog Announcement
React Server Components는 Meta에서 수년간 유지 및 관리해 온 기술로,
현재 전 세계 주요 기업의 5천만 개 이상의 웹사이트와 제품에 적용되어 있다.
이번에 발견된 취약점(CVE-2025-55182)은 “React2Shell”로 명명되었다.
보안 연구자 Lachlan Davidson이 11월 29일 Meta에 제보하였으며,
수요일 패치 배포와 함께 세부 사항이 공개되었다.
이 취약점은 위험도 평가에서 10점 만점에 10점(Critical)을 기록했다.
미국 사이버 보안 및 인프라 보안청(CISA)은
React Server Components(RSC)에 영향을 미치는
이 심각한 보안 결함이 실제 공격에 악용된 사례가 확인됨에 따라,
금요일 자사의 ‘알려진 악용 취약점(KEV)’ 목록에 공식 추가했다.
──────────────────────────────────────────────
2. 분석
2.1 취약점 개요
2.1.1 취약점 ID
2.1.2 특징
ㆍ 유형: CVE-2025-55182는 RSC 환경에서 발생하는
‘안전하지 않은 역직렬화(Insecure Deserialization)’ 취약점이다.
ㆍ 공격 방식: 인증되지 않은 원격 공격자가 취약한 React Server Function 엔드포인트로
특수하게 조작된 페이로드를 전송하여 악용한다.
ㆍ 영향: 취약점 악용에 성공할 경우, 서버 권한으로 원격 코드 실행(RCE)이 가능하다.
2.1.3 관측된 악용 활동
구글 위협 인텔리전스(GTIG)에 따르면,
취약점 공개 직후 여러 지역과 산업군에서 다양한 페이로드와 악용 시도가 포착되었다.
특히 중국 연계 사이버 스파이 그룹 및 금전적 목적의 공격 그룹의 활동이 두드러졌다.
ㆍ MINOCAT
MINOCAT UNC6600 그룹은 이 취약점을 악용하여 MINOCAT 터널러를 유포했다.
공격자는 Bash 스크립트를 실행하여 숨김 디렉터리 생성, 기존 ntpclient 프로세스 종료,
MINOCAT 바이너리 다운로드를 수행했다.
이후 cron 작업 등록, systemd 서비스 생성, 쉘 설정 파일 변조를 통해
지속적인 실행(Persistence)을 확보했다.
ㆍ SNOWLIGHT
SNOWLIGHT UNC6586 그룹은 원격 명령 실행 후
cURL/wget을 이용해 스크립트를 다운로드하고,
SNOWLIGHT 다운로더를 설치 및 실행했다.
SNOWLIGHT는 오픈 소스 백도어인 VSHELL(Go 언어 기반)의 구성 요소로,
C2 서버에 HTTP GET 요청을 보내 정상 파일로 위장한 추가 페이로드를 받아 감염을 확산시킨다.
ㆍ COMPOOD
COMPOOD UNC6588 그룹은 스크립트를 통해 COMPOOD 백도어를 다운로드하고,
이를 Vim 에디터로 위장하여 실행하는 흐름을 보였다.
추가적인 후속 활동은 뚜렷하게 관측되지 않았으며 구체적인 공격 동기는 불명확하나,
과거 사례를 볼 때 중국 연계 스파이 활동과 관련이 깊다.
ㆍ HISONIC
HISONIC UNC6603 그룹은 Go 기반 백도어인 HISONIC의 최신 변종을 배포했다.
이들은 Cloudflare Pages나 GitLab 같은 정상 서비스를 악용해
암호화된 설정 값을 받아오도록 구성했다. 설정 값은 XOR 인코딩되어 문자열 내부에 삽입되어 있으며,
시작/종료 마커를 통해 파싱된다.
주로 APAC 지역의 AWS 및 Alibaba Cloud 인스턴스를 표적으로 삼고 있다.
아마존 웹 서비스(AWS) 보고서에 따르면,
‘Earth Lamia’와 ‘Jackpot Panda’라는 중국 연계 위협 그룹 또한
해당 취약점 악용을 시도한 정황이 포착되었다.
──────────────────────────────────────────────
2.2 기술적 원리
2.2.1 React Server Components (RSC)
RSC는 컴포넌트를 브라우저(클라이언트)가 아닌 서버에서 먼저 실행하여 화면을 구성하는 기술이다.
이를 통해 데이터 처리와 렌더링을 서버에서 수행하므로
민감한 정보가 클라이언트에 노출되는 것을 방지하고,
초기 로딩 속도와 보안성, 유지보수성을 향상시킨다.
Next.js와 같은 최신 프레임워크에 기본적으로 통합되어 있다.
2.2.2 Flight Protocol
Flight Protocol은 RSC 환경에서 서버와 클라이언트 간의 컴포넌트 트리 및 상태 정보를 교환하기 위한
React 전용 직렬화·전송 프로토콜이다.
서버는 데이터를 ‘청크(Chunk)’ 단위로 직렬화하여 전송하고,
클라이언트는 이를 조립하여 UI를 렌더링한다.
2.2.3 Prototype Pollution 개념
Prototype Pollution(프로토타입 오염)은
공격자가 __proto__, constructor, prototype 등의 특수 속성에 접근하여
기본 객체(Object.prototype)를 조작하는 JavaScript 취약점이다.
이를 통해 애플리케이션 내의 모든 객체에 영향을 미치는 악성 속성 값을 주입할 수 있다.
React 환경에서도 서드파티 라이브러리나 Props 병합 과정에서 이와 유사한 원리로 취약점이 발생할 수 있다.
──────────────────────────────────────────────
2.3 취약점 코드 상세 분석
2.3.1 취약점 개념
React는 요청된 키가 객체에 실제로 설정되어 있는지 검증하지 않는다.
이로 인해 앞서 설명한 Prototype Pollution 원리를 이용해 객체 프로토타입에 접근할 수 있으며,
특정 페이로드를 전송하면 서버에서 Function 생성자로 역직렬화되는 문제가 발생한다.
[그림 2] 취약점 원인 코드 및 PoC 실행 결과
2.3.2 CVE-2025-55182 PoC Code
취약점을 이용하면 공격자는 Function 생성자를 확보할 수 있다.
이를 악용하기 위해 공격자가 제어 가능한 문자열(함수 코드)을 인자로 넣어 Function 생성자를 호출하고,
생성된 함수를 즉시 실행하도록 유도하는 호출 가젯(Call Gadget)을 찾아야 한다.
해당 PoC(개념 증명) 코드에서는 취약점 트리거를 위해 getChunk 함수를 사용한다.
[그림 3] GitHub 저장소 facebook/react
[그림 4] PoC payload 코드
1. PoC 코드가 역직렬화되는 과정에서 chunk[1]에 포함된 “$@0” 구문이 감지된다.
2. GitHub 저장소의 코드 흐름에 따라 getChunk(response, 0)이 호출된다.
3. 이때 ID가 0인 청크는 해석된(resolved) 값이 아닌,
0번 청크 객체(Raw Chunk) 자체가 반환된다.
결과적으로 chunk[1]은 Raw Chunk(0)을 참조하게 된다.
PoC의 “then”: “$1:proto:then” 구문은 $1:proto:then을 참조하도록 설정되어 있다.
여기서 $1이 Raw Chunk를 가리키므로,
__proto__를 통해 Chunk.prototype에 접근할 수 있게 되고,
최종적으로 then은 Chunk.prototype.then을 참조하게 된다.
[그림 5] ReactFlightReplyServer.js/Chunk()
다음으로 “status”: “resolved_model” 설정에 의해
chunk.status가 RESOLVED_MODEL 상태가 되며,
이에 따라 initializeModelChunk(chunk) 함수가 호출된다.
[그림 6] ReactFlightReplyServer.js/initializeModelChunk()
이후 “value”: ‘{“then”: “$B0”}’ 설정으로 chunk.value 값이 세팅되며,
코드 흐름상 reviveModel 함수의 인자인 rawModel로 전달된다.
[그림 7] ReactFlightReplyServer.js/reviveModel()
그리고 parseModelString 함수가 key = “then”, value = “$B0” 값으로 호출된다.
[그림 8 ReactFlightReplyServer.js/parseModelString()
1. PoC 코드의 _response 객체는 parseModelString 내부의 $B 처리 분기에서 직접 참조된다.
2. “$B0”는 id = 0으로 해석되며, prefix = response._prefix에는
PoC에서 설정한 공격 구문
(“process.mainModule.require(‘child_process’).execSync(‘calc’);”)이 대입된다.
3. response._formData.get(blobKey); 부분에서
_formData.get이 $1:constructor:constructor로 오염되어 설정되어 있으므로,
정상적인 FormData 조회가 아닌 Function(blobKey) 생성자 호출로 치환된다.
4. 결과적으로 Function(blobKey)가 생성하는 함수의 본문에
PoC 내의 악성 문자열(페이로드)이 주입되며,
후속 흐름에서 이 함수가 실행될 때 원격 코드 실행(RCE)이 발생한다.
──────────────────────────────────────────────
3. 대응
3.1 수동 식별 가이드
① 프로젝트 디렉터리로 이동한 뒤 node_modules 폴더를 확인한다.
② 설치된 패키지를 확인하고, 아래 항목이 있는지 검토한다.
ㆍ react-sever-dom-webpack
ㆍ react-sever-dom-parcel
ㆍ react-sever-dom-turbopack
ㆍ next
──────────────────────────────────────────────
3.2 영향 받는 제품 및 해결 방안
알려진 ‘영향 받는 버전’ 범위와 현재 설치된 버전을 대조해야 한다.
영향 받는 버전을 사용 중인 경우, 아래 해결 방안에 따라 즉시 최신 버전으로 업데이트할 것을 권고한다.
──────────────────────────────────────────────
3.3 WAF 규칙 배포
Google은 이 취약점과 관련된 공격 시도를 탐지하고 차단하도록 설계된 Cloud Armor 웹 애플리케이션 방화벽(WAF) 규칙을 배포했다.
[그림 9] Google WAF 규칙
──────────────────────────────────────────────
3.4 침해 지표
Google 위협 인텔리전스에서 발표한 IOC 정보는 다음과 같다.