[web] Prototype Pollution(프로토타입오염) 취약점 개요

들어가며

웹 취약점 진단 수행 중 웹 애플리케이션의 클라이언트 측(Javascript) 코드에서 Prototype Pollution 취약점(프로토타입 오염)이 발견되었다. 취약점에 대해 개념을 정리하고 어떻게 코드를 분석했는지 소개한다. 물론 틀린부분이 있을 수 있으므로 다양한 의견으로 알려주시면 감사하겠습니다.

 

취약점 개요

자바스크립트는 프로토타입 기반의 객체 지향 언어이다. 모든 객체는 숨겨진 속성 '__proto__'를 통해 어떤 프로토타입 객체를 참조하며, 이 프로토타입에 정의된 속성과 메서드는 해당 객체 및 그 하위 객체들이 상속받는다. Prototype Pollution(이하 PP)은 공격자가 이 프로토타입 객체에 임의의 속성을 주입함으로써 기본 객체의 동작을 변경할 수 있는 취약점이다.

유효 범위는 애플리케이션 전역에서 공유되는 객체인 경우 전체가 될수 있으며, 함수의 프로토타입에 주입이 가능한 경우 로직이 조작되거나 의도치 않게 동작하게 된다. 심각한 경우 서비스 거부(DoS)나 원격 코드 실행(RCE)이 가능해진다.

PP 취약점은 자바스크립트 객체를 병합하거나 복제하는 기능을 구현할 때, 입력 값을 검증하지 않아 발생한다. 예를 들어 객체를 재귀적으로 병합(merge)하는 함수가 사용자로부터 전달된 객체의 키 이름을 필터링하지 않고 기존 객체에 적용하면, __proto__와 같은 특수 키가 포함될 경우 대상 객체의 프로토타입이 조작될 수 있다. 이런 취약점은 과거에 jQuery, Lodash, Express, Minimist, Hoek와 같은 유명 자바스크립트 라이브러리에서 발견되어 패치된 전력이 있을 정도로 광범위하게 존재한다.

 

 

취약점 발견 과정 및 분석

// 취약한 객체 병합 함수 예시
function mergeObjects(target, source) {
  for (const key in source) {
    target[key] = source[key];  // 사용자 입력 객체를 키 필터링 없이 병합
  }
}

// 기본 설정 객체에 사용자 입력을 병합
const defaultConfig = { theme: "light", sidebar: true };
const userData = getUserInput();  // 예: URL 쿼리스트링이나 폼 입력 등
mergeObjects(defaultConfig, userData);

'mergeObjects' 함수를 통해 사용자 제공 객체 userDatadefaultConfig에 병합한다. 이때 userData의 키에 대한 검사나 필터링이 없으므로, 악의적인 사용자가 userData에 특수 키 __proto__를 포함시킬 경우 defaultConfig의 프로토타입이 오염될 수 있다. 즉, defaultConfig.__proto__에 공격자가 넣은 객체게 할당되어 전역 객체(Object.prototype)의 속성이 변조될 수 있다.

코드 리뷰 만으로 의심 지점을 식별했다면, 실제로 취약점이 존재하는지는 콘솔에서 취약 코드를 실행하여 검증할 수 있다. 구체적으로 어플리케이션의 입력 지점(URL 파라미터)에 __proto__를 포함한 페이로드를 주입한 후 브라우저 개발자 도구 콘솔에서 Object.prototype을 확인한다.

- 예를 들어 웹 페이지의 URL에 ?__proto__[evil]=1과 같은 쿼리 스트링을 추가하고 페이지를 로드한 뒤, 콘솔에서 Object.prototype.evil 값을 확인할 때 값이 1로 나타난다면, 이는 해당 입력으로 전역 프로토타입 객체가 오염되었음을 의미한다.

콘솔에서 테스트해볼 수 있는 예제를 몇가지 제공한다. PoC는 다양하게 응용가능하다.

console.log(Object.prototype.isAdmin);  // 공격 전: undefined

// __proto__ 키를 포함한 악성 payload 객체 (예: 사용자 입력으로부터 생성된 객체)
let payload = JSON.parse('{"__proto__": { "isAdmin": true }}');

// payload를 새 객체로 병합 (취약한 동작 시뮬레이션)
Object.assign({}, payload);

console.log(Object.prototype.isAdmin);  // 공격 후: true

위 과정을 통해 Object.prototype.isAdmin 값이 true로 설정되는 것을 확인했다. 이는 Object.assign으로 병합하는 과정에서 __proto__ 속성이 특별하게 처리되어 전역 Object 프로토타입에 isAdmin 속성이 주입된 것이다.

 

 

취약점 발생 시 영향

- 권한 상승 및 로직 변조: 공격자는 프로토타입에 보안과 관계된 속성을 주입하여 애플리케이션의 접근 제어나 로직을 우회할 수 있다. 예를 들어 애플리케이션이 user.isAdmin 속성으로 관리자 권한을 검사한다면, 공격자는 모든 객체의 프로토타입에 isAdmintrue로 설정해버림으로써 인증 없이 관리자 권한을 얻을 수 있다.

- 데이터 변조 및 무결성 훼손: 공격자가 프로토타입에 중요한 설정 값을 주입하거나 기본 동작을 변경하면 애플리케이션의 데이터 무결성에 문제가 생기고 부적절한 동작이 발생한다. 예를 들어 모든 객체에 대해 defaultTimeout 값을 0으로 오염시켜 버리면 타임아웃 설정이 무력화될 수 있고, toJSON 등의 메서드를 악의적으로 덮어써서 로깅이나 직렬화 과정을 교란할 수도 있다. 이러한 변조는 발견하기 어려워 애플리케이션이 예기치 않은 방식으로 동작하도록 만다.

- 서비스 거부(DoS): 프로토타입 오염을 통해 의도적으로 예외 상황을 일으키거나 무한 루프를 유발하여 애플리케이션을 마비시킬 수 있습니다. 예를 들어 모든 객체의 기본 메서드인 toString을 문자열이나 빈 함수로 덮어쓰면(JS 엔진은 모든 객체에 toString 메서드가 있다고 가정하기 때문에) 애플리케이션 곳곳에서 오류가 발생하여 전체 서비스가 중단될 수 있다.

https://learn.snyk.io/lesson/prototype-pollution/?ecosystem=javascript

 

What is prototype pollution? | Tutorial & examples | Snyk Learn

Learn what JavaScript prototype pollution is and how to prevent it.

learn.snyk.io

 

- 크로스 사이트 스크립팅(XSS) 등 2차 공격: 클라이언트 사이드에서 프로토타입 오염은 종종 DOM XSS로 이어질 수 있다. 공격자는 프로토타입에 악의적인 스크립트 문자열이나 DOM 조작용 속성을 심어놓고, 애플리케이션 내 다른 컴포넌트가 그 속성을 사용하도록 유도한다. 예를 들어, PP 속성 값이 나중에 innerHTML에 삽입되거나 eval로 실행되는 취약한 코드가 있다면 결국 임의 스크립트 실행이 발생한다.

https://www.synack.com/exploits-explained/persisting-through-a-client-side-prototype-pollution/

 

Persisting Through a Client-Side Prototype Pollution

In this blog, I’ll consolidate that information, share my understanding of CSPP vulnerabilities, and provide recommendations for prevention.

www.synack.com

 

 

 

취약점 진단 도구

Burp Suite Pro 에서는 DOM Invader 도구를 제공하고 있다. 브라우저 내에서 실행되는 클라이언트 측 코드(DOM 기반 취약점)을 탐색하고, 공격 페이로드를 주입하여 보안 취약점을 발견할 수 있게 해주는 확장 도구이다. PP 취약점은 URL 파라미터 > 자바스크립트 객체 변환 > 앱 로직 반영의 순서로 발생하는데, DOM Invader는 이 과정을 자동으로 확인해 준다.

DOM Invader 설정에서 Prototype Pollution 체크를 활성화하면, Burp는 자동으로 URL 파라미터, 프래그먼트(#), postMessage 데이터 등 입력 경로(source)에 __proto__constructor.prototype 형태의 페이로드를 삽입한다. DOM Invader는 앱 코드에서 이 값이 객체 병합에 사용되는지, Object.prototype에 전파되는지를 추적한다.

 

 

패널에는 다음 정보가 표시된다.

 

Source: 페이로드가 삽입된 위치(예: URL 쿼리 파라미터 foo[__proto__][pp]=1)
Sinks: 해당 값이 실제로 도달한 DOM API나 merge 함수(Object.assign, $.extend, _.merge 등)
Evidence: 오염이 확인되면 Burp가 Object.prototype에서 새 속성이 발견되었다는 PoC를 표시

 

 

결론

프로토타입 오염 취약점은 자칫 간과하기 쉽지만 공격자가 이를 이용하면 애플리케이션 전반에 중대한 영향을 끼칠 수 있는 논리 폭탄과 같다. 프로토타입 기반 언어인 자바스크립트의 특성을 악용하는 공격이므로, 개발자는 평소 객체 병합이나 JSON 파싱 로직을 구현할 때 보안 가이드라인을 준수해야 한다.

반응형

'Security > WEB' 카테고리의 다른 글

[웹 크롤링] cloudflare 차단 우회  (1) 2023.12.27
[웹해킹] OAST / OOB(Out-of-Band) Testing  (0) 2023.05.27
[PKI] 인증서 관리 규격  (1) 2022.12.03
제 3자 쿠키 허용, 왜 위험할까?  (0) 2022.10.30
[WEB] Client Side Storage  (0) 2022.10.09