문제 개요
Dreamhack Level 3 XSS 필터링 우회 문제이다.
/flag 페이지에서 XSS 스크립트를 삽입하면 check_xss 함수가 /vuln API를 호출하고, 해당 API에서 xss_filter 함수로 필터링 후 반환한다.
필터링 목록
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필터링되는 문자열:
script,on,javascriptwindow,self,this,document,location(,),&#
우회 기법
1. 문자열 치환 필터 우회
의심 구문을 제거(치환)하는 방식의 필터는, 필터링 키워드 사이에 새로운 필터링 키워드를 삽입해 우회할 수 있다.
(x => x.replace(/onerror/g, ''))('<img oneonerrorrror=promonerrorpt(1)>')
→ <img onerror=prompt(1) />
one[onerror]rror=prom[onerror]pt(1) — 대괄호 안의 문자열이 제거되어 onerror, prompt 완성.
2. 활성 하이퍼링크 (javascript: 스키마)
HTML 마크업에서 URL에 javascript: 스키마를 사용하면 자바스크립트 코드를 실행할 수 있다.
<a href="\1\4jAVasC\triPT:alert(document.domain)">Click me!</a>
<iframe src="\1\4jAVasC\triPT:alert(document.domain)">브라우저의 정규화(Normalization) 과정을 이용한다. \x01, \x04, \t 같은 특수 문자들이 정규화 과정에서 제거되고 스키마의 대소문자가 통일된다.
| 문자 | 16진수 | 설명 |
|---|---|---|
\x01 | 0x01 | SOH - Start of Heading |
\x04 | 0x04 | EOT - End of Transmission |
\t | 0x09 | TAB - Horizontal Tab |
<!-- HTML 엔티티 인코딩 조합 -->
<a href="\1JavasCr\tip&tabt;:alert(document.domain);">Click me!</a>
javascript:스키마를 VSCode 등의 에디터로 정규화하면 제대로 이루어지지 않는 경우가 있다. 이럴 때는 LLM(GPT, Claude 등)을 사용해 정규화하는 것이 효과적이다.
3. 태그와 속성 기반 필터 우회
대소문자 필터 우회
// 소문자만 검사하는 필터
x => !x.includes('script') && !x.includes('on')
// 대소문자 통합 필터
x => !x.toLowerCase().includes('script') && !x.toLowerCase().includes('on')대소문자 통합 필터는 ScRiPt, SCRIPT 등으로 우회 불가능하다. 다른 기법을 조합해야 한다.
관련 문제
- https://dreamhack.io/wargame/challenges/level3 (XSS Filtering Bypass Advanced)