Client Side Template Injection 취약점
프레임워크를 사용하면 DOM 내의 데이터를 수정하기에 간편하고, 웹 페이지를 컴포넌트화 하여 작성할 수 있기 때문에 개발하는데에 있어서 굉장히 편리하다.
보편적으로 사용되는 프레임워크 종류) Vue, React, AngularJS 등
Client Side Template Injection
- 이용자의 입력 값이 client side template framework에 의해 템플릿으로 해석되어 렌더링될 때 발생한다.
- 개발의 편의성을 높여주는 프레임워크지만 잘못된 방식으로 사용할 경우, 이를 통해 XSS 취약점까지 연계하는 것이 가능하다.
Vue
- Vue 혹은 Vue.js라고 불리는 프론트엔드 프레임워크는 2014년 출시된 프레임워크이며, Google의 한 연구원인 Evan You가 개발하였다.
- Vue는 오픈소스 자바스크립트 프레임워크로, 이용자 인터페이스나 Single Page Application을 빌드할 때 사용된다.
다음은 Vue의 예제 코드이다.
<script src="https://unpkg.com/vue@3"></script>
<div id="app">{{ message }}</div>
<script>
Vue.createApp({
data() {
return {
message: 'Hello Vue!'
}
}
}).mount('#app')
</script>
{{ }}으로 감싸진 부분이 Vue 템플릿 부분이다. 해당 템플릿 내에서 문자열을 표시하거나 자바 스크립트 표현식을 실행할 수 있다. 만약 여기서 템플릿 내부에 공격자의 입력이 들어가 Template Injection 취약점이 발생한다면, XSS 공격으로 이어질 수 있다.
다음은 이용자의 입력을 그대로 페이지에 출력하여 Vue Template Injection에 취약한 예제 소스 코드이다.
<script src="https://unpkg.com/vue@3"></script>
<div id="app">
<?php echo htmlspecialchars($_GET['msg']); ?>
</div>
<script>
Vue.createApp({
data() {
return {
message: 'Hello Vue!'
}
}
}).mount('#app')
</script>
이용자로부터 입력받은 GET 메소드의 msg 파라미터를 그대로 출력하지만, htmlspecialchars 함수를 통해 꺽쇠 문자가 모두 인코딩되기 때문에 일반적인 XSS 공격은 불가능하다. 하지만 출력되는 값이 Vue의 템플릿으로 사용될 수 있기 때문에 Template Injection이 발생한다.
Vue Template Injection이 발생하는지 확인하는 간단한 방법
- 템플릿을 이용해 산술 연산을 수행해보면 된다.
- {{1+1}} 과 같은 산술 연산 형태의 템플릿을 입력했을 때, 연산이 실행된 형태인 2가 출력된다면 Tempalte Injection이 발생하는 것으로 확인할 수 있다.
Teplate Injection이 발생할 때 자바스크립트 코드 실행으로 연계하는 방법
- 보통 생성자 (constructor)를 이용한다.
- Vue 템플릿 컨텍스트 내에서 생성자에 접근하여 임의 코드에 해당하는 함수를 생성하고, 이를 호출하는 방식으로 XSS 공격이 가능하다.
- Vue 템플릿 컨텍스트 내에서 생성자에 접근하는 방법은 여러가지가 존재하지만 대표적으로 {{_Vue.h.constructor}}를 이용해 접근할 수 있다.
- 이를 이용하여 {{_Vue.h.constructor("alert(1)")()}} 처럼 익스플로잇 코드를 만들 수 있다.
AngularJS
- AngularJS는 2010년 출시된 프론트엔드 프레임워크로 Google에서 개발되었다.
- AngularJS는 타입스크립트 기반의 오픈소스 프레임워크이며 CLI 도구에서 다양한 기능을 제공하기 때문에 개발을 편리하게 해주는 프레임워크 중 하나이다.
다음은 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>
<div>
<label>Name:</label>
<input type="text" ng-model="yourName" placeholder="Enter a name here">
<hr>
<h1>Hello {{yourName}}!</h1>
</div>
</body>
</html>
Vue와 마찬가지로 {{ }}로 감싸진 부분이 AngularJS 템플릿 부분이며, 해당 템플릿 내에서 문자열을 표시하거나, 자바스크립트 표현식을 실행할 수 있다.
다음은 AngularJS Template Injection에 취약한 예제 소스 코드이다.
<!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['msg']); ?>
</body>
</html>
이용자로부터 입력받은 GET 메소드의 msg 파라미터를 그대로 출력하지만, htmlspecialchars 함수를 통해 꺽쇠 문자가 모두 인코딩되기 때문에 일반적인 XSS 공격은 불가능하다. 하지만 출력되는 값이 AngularJS의 템플릿으로 사용될 수 있기 때문에 Template Injection이 발생한다.
Vue와 마찬가지로 템플릿 내부에서의 산술 연산이 실행된 결과가 출력되는지의 여부로 Template Injection을 탐지할 수 있다. 또한 AngularJS 템플릿 컨텍스트 내부에서 생성자 함수에 접근할 수 있기 때문에 이를 이용하여 XSS 공격으로 연계가 가능하다.
AngularJS 템플릿에서 생성자에 접근하기 위해서는 {{ constructor.constructor }} 로 접근할 수 있다. 이를 이용하면 임의 코드에 해당하는 함수를 생성하고, 호출하여 공격할 수 있다: {{ constructor.constructor("alert(1)")() }}
프론트엔드 프레임워크를 사용할 때 주의할 점
- Client Side Template Injection은 꺽쇠와 같은 특수문자가 필터링 되어있더라도 XSS로 연계할 수 있어 파급력이 높은 취약점이다.
- 프론트엔드 프레임워크를 이용할 때에는 반드시 production mode로 코드를 빌드하여 사용하고, 이용자의 입력이 템플릿으로 인식되지 않도록 유의하여야 한다.