본문으로 건너뛰기

Prototype Pollution: JS의 숨겨진 취약점

JavaScript의 prototype 체인을 오염시켜 앱 전체 동작을 바꾸는 공격 기법이다. 이름은 생소해도, 실전 CTF와 Bug Bounty에서 꽤 자주 등장한다.

원리

JS에서 모든 객체는 __proto__를 통해 상위 프로토타입을 참조한다.

const obj = {};
obj.__proto__.isAdmin = true;

const newObj = {};
console.log(newObj.isAdmin); // true ← 오염됨

obj.__proto__를 건드리면 Object.prototype 자체가 변조되어, 이후 생성되는 모든 객체에 영향을 준다.

공격 시나리오

1. 권한 우회

// 서버 코드 (Express)
if (req.user.isAdmin) { ... }

// 공격 payload (JSON merge 취약점)
{ "__proto__": { "isAdmin": true } }

lodash.merge, jquery.extend 같은 deep merge 함수들이 대표적인 진입점이다.

2. RCE로의 확장

Node.js 환경에서 child_process 관련 옵션이 prototype에 주입되면 Remote Code Execution까지 이어질 수 있다.

// 특정 라이브러리에서 실행 옵션을 prototype에서 읽는 경우
{ "__proto__": { "shell": "bash", "env": { "NODE_OPTIONS": "--inspect=0.0.0.0" } } }

탐지 & 방어

탐지:

  • Object.prototype에 예상치 못한 속성이 생겼는지 주기적 체크
  • JSON.parse__proto__, constructor 키 필터링

방어:

  • Object.create(null) — prototype 없는 순수 객체 사용
  • Object.freeze(Object.prototype) — prototype 동결
  • 신뢰할 수 없는 입력에 deep merge 금지

CTF 팁

Prototype Pollution 문제가 나오면 __proto__, constructor.prototype 두 경로를 모두 시도해보자. 라이브러리 버전을 확인하고 알려진 CVE를 체크하는 것도 필수다.

lodash < 4.17.19, jquery < 3.4.0 — 대표적인 취약 버전

작은 객체 하나가 앱 전체를 흔드는 게 Prototype Pollution의 묘미다. 🥞