CSTI(Client Side Template Injection)는 클라이언트 측에서 발생하는 공격으로, 템플릿 엔진을 사용하는 클라이언트 측의 코드에서 발생한다. 예를 들어, React, AngularJS, Vue.js 등의 클라이언트 측 자바스크립트 프레임워크에서 발생할 수 있다. CSTI는 클라이언트 측에서 사용되는 템플릿 엔진에 취약점이 있을 때 발생하며, 악의적인 스크립트가 클라이언트 측에서 실행될 수 있다.
Vue는 오픈소스 자바스크립트 프레임워크로, 이용자 인터페이스나 Single Page Application을 빌드할 때 사용힌다. Vue에 대한 상세한 정보는 https://vuejs.org/ 에서 확인할 수 있다.
아래 코드는 URL 파라미터의 template 값으로 Vue.js의 template 태그 안에 들어가는 값을 동적으로 설정하는 예시이다. 하지만 사용자가 template 값에 임의의 코드를 넣을 경우 CSTI 취약점이 발생할 수 있다.
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.13/dist/vue.js"></script>
<div id="app">
<h1>Vue Template Injection(@silver35)<h1>
<?php echo htmlspecialchars($_GET['template']); ?>
</div>
<script>
new Vue({
el: '#app'
});
</script>
따라서, 아래와 같이 {{7*7}}을 입력했을 때 연산이 실행된 상태인 49가 출력되기 때문에 Template Injection이 발생한다.
Template Injection이 발생할 때 이를 임의 자바스크립트 코드 실행으로 연계하는 방법으로 보통 생성자(constructor)를 이용한다. Vue 템플릿 컨텍스트 내에서 생성자에 접근하여 임의 코드에 해당하는 함수를 생성하고, 이를 호출하는 방식으로 XSS 공격이 가능하다. 현재는 vue2를 사용함으로 아래와 같이 익스플로잇을 하면 된다.
{{constructor.constructor('alert(1)')()}}
AntularJS는 타입스크립트 기반의 오픈소스 프레임워크이며 CLI 도구에서 다양한 기능을 제공하기 때문에 개발을 편리하게 해주는 프레임워크이다. AngularJS의 자세한 정보는 https://angular.io/docs 에서 확인할 수 있다.
아래 코드는 URL 파라미터의 template 값으로 AngularJS의 template 태그 안에 들어가는 값을 동적으로 설정하는 예시이다. 하지만 사용자가 template 값에 임의의 코드를 넣을 경우 CSTI 취약점이 발생할 수 있다. ng-app은 AngularJS에서 애플리케이션 모듈을 식별하기 위한 지시자이며 ng-app을 사용하여 AngularJS 애플리케이션을 정의해야한다.
<!doctype html>
<html ng-app>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.8.2/angular.min.js"></script>
</head>
<body>
<?php echo htmlspecialchars($_GET['template']); ?>
</body>
</html>
Template Injection이 발생할 때 이를 임의 자바스크립트 코드 실행으로 연계하는 방법으로 보통 생성자(constructor)를 이용한다. AngularJS 템플릿내에서 생성자에 접근하여 임의 코드에 해당하는 함수를 생성하고, 이를 호출하는 방식으로 XSS 공격이 가능하다.
{{constructor.constructor('alert(1)')()}}
이용자의 입력값을 템플릿으로 인식하지 않도록 해야한다. 이를 위해 입력값에 대한 유효성 검사를 수행하고, 출력값에 대해서는 적절한 이스케이핑 처리를 해주어야 한다.
아래 코드는 Vue.js의 데이터 바인딩 기능을 이용하여, 사용자의 입력값을 {{}}를 사용하여 출력한다. Vue.js에서 데이터 바인딩(data binding)이란, Vue 인스턴스의 데이터와 HTML 템플릿을 연결하는 기능이며 HTML 템플릿 내에서 중괄호({{ }})를 사용하여 Vue 인스턴스의 데이터를 출력한다. 이를 통해 Vue.js의 XSS(Cross-Site Scripting) CSTI 취약점을 해결할 수 있다.
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.13/dist/vue.js"></script>
<div id="app">
<h1>Vue Template Injection(@silver35)<h1>
{{ templateData }}
</div>
<script>
new Vue({
el: '#app',
data: {
templateData: ''
},
created: function() {
var urlParams = new URLSearchParams(window.location.search);
var template = urlParams.get('template');
this.templateData = template;
}
});
</script>
따라서, 아래와 같이 템플릿 형식을 입력하여도 사용자의 입력값이 그대로 출력된다.
참고자료)
https://book.hacktricks.xyz/pentesting-web/client-side-template-injection-csti
https://learn.dreamhack.io/329