[web] SSTI 알아보기

2026. 2. 15. 00:38·Security/웹

0. SSTI란?

SSTI는 사용자 입력이 서버 템플릿 엔진에서 코드처럼 해석되는 취약점이다.
즉, 단순 문자열 출력이 아니라 템플릿 문법으로 실행된다는 점이 핵심이다.

 

1. Template 엔진이란?

템플릿 엔진은 고정된 서식(Template)과 변하는 데이터(Data)를 결합하여 완성된 문서(주로 HTML)를 생성해 주는 소프트웨어 도구이다.

그러면 template란?

템플릿은 고정된 서식(Template)으로 변하는 데이터(Data)로 {{}}등 여기에 데이터가 들어가고 나머지 HTML구조등을 말한다. 템플릿 엔진은 {{}}안에 데이터를 해석해 템플릿과 합쳐주는 도구이다.

 

2. Jinja2는 무엇인가?

Jinja2는 웹 프레임워크가 아니라 Python 템플릿 엔진 라이브러리다.
Flask가 기본 템플릿 엔진으로 Jinja2를 사용하기 때문에 자주 함께 언급된다.

  • 웹 프레임워크 (Flask, Django 등) 사용자가 어떤 주소(URL)로 요청을 보냈는지 확인하여 연결(라우팅)하고, 데이터베이스에서 정보를 조회하거나 저장하며, 로그인 세션을 관리하는 등 웹 서버의 전체적인 흐름과 로직을 담당합니다.
  • 템플릿 엔진 (Jinja2) 프레임워크가 로직 처리를 끝내고 넘겨준 데이터를 받아서, HTML 파일의 지정된 위치에 값을 채워 넣고 최종적으로 보여질 문서를 완성하는 텍스트 처리 작업만 담당합니다.
 
안전한 경우는 템플릿 파일을 고정하고 변수만 전달하는 방식이다.
return render_template("index.html", name=user_data)

 

 

문제가 되는 경우는 사용자 입력을 템플릿으로 직접 실행하는 방식이다.

return render_template_string(user_input)

이 패턴에서는 사용자 입력이 템플릿 문법으로 해석되어 SSTI가 발생할 수 있다.

 

주로 사용하는 ssti페이로드이다

{{config.__class__.__init__.__globals__['os'].popen('ls').read()}}

3. 근데 그러면  어떤 코드를 실행할까?

Jinja2 템플릿 안에서는 import os 같은 파이썬의 정석적인 코드를 사용할 수 없도록 막혀있는 샌드박스 환경이다. 그런데 어떻게 센드박스 밖에 있는 함수를 실행 가능할까?

 

웹 애플리케이션(Flask)이 실행될 때 파이썬 인터프리터는 하나의 거대한 프로세스로 동작합니다. 이 프로세스 안에는 이미 수많은 기본 라이브러리(str, int, list 등)와 프레임워크(Flask, Jinja2), 그리고 그들이 내부적으로 사용하는 모듈(os, sys 등)이 전부 로딩되어있다

 

파이썬에서 모든 것은 객체이다. 객체는 상속되어 있으며 부모를 찾아가서, 다시 그 부모의 다른 자식들을 조회하는 식으로 메모리에 로드된 모든 클래스에 접근할 수 있습니다.

 

진입점으로 사용하는 객체 

  1. 파이썬 기본 자료형 (Primitives) 가장 흔하게 사용되는 방식입니다. 별도의 변수 이름 없이 기호만으로 표현 가능하기 때문에, config 같은 특정 단어를 차단하는 보안 장비(WAF)를 우회하기 매우 좋습니다.
  • 빈 문자열 "" 또는 '' 가장 기본적이고 많이 쓰이는 진입점입니다. 타입: str 경로: "".class 는 str 클래스를 반환합니다.
  • 빈 리스트 [] 문자열 따옴표가 필터링될 때 대안으로 사용합니다. 타입: list 경로: [].class 는 list 클래스를 반환합니다.
  • 빈 튜플 () 리스트와 유사하게 사용됩니다. 타입: tuple 경로: ().class 는 tuple 클래스를 반환합니다.
  • 빈 딕셔너리 {} 타입: dict 경로: {}.class 는 dict 클래스를 반환합니다.
  • 숫자 (예: 1, 0) 타입: int 경로: (1).class 는 int 클래스를 반환합니다.

 

2. Flask/Jinja2 전역 객체 (Globals) 프레임워크가 템플릿 렌더링을 위해 기본적으로 삽입해 둔 객체들입니다.

  • config Flask의 설정 객체입니다. 앞서 설명했듯 1순위로 확인하는 타깃입니다.
  • request 현재 요청 객체입니다.
  • self 현재 렌더링 되고 있는 템플릿 그 자체(Template Instance)를 가리킵니다. self.__dict__를 통해 현재 템플릿에 로드된 변수 목록을 확인할 때도 쓰입니다.
  • g Flask에서 요청 처리 기간 동안 데이터를 보관하는 전역 객체입니다

3. Jinja2 유틸리티 및 함수 (Helpers) 객체보다는 함수(Callable) 형태의 진입점이 필요할 때 사용합니다. 함수 객체는 globals 속성을 직접 가지고 있는 경우가 많아, 상속 계층을 많이 타지 않고도 바로 모듈 영역으로 넘어갈 수 있는 지름길이 되기도 합니다.

lipsum 랜덤 텍스트 생성 함수입니다.

cycler 리스트의 값을 순환하며 반환하는 Jinja2의 헬퍼 클래스입니다.

joiner 문자열을 합칠 때 사용하는 헬퍼 클래스입니다.

 

{{lipsum.__globals__.os}}@asd.com

Jinja2가 파이프(|)를 해석하는 방식

Jinja2 템플릿 엔진이 {{ "값" | 무언가 }}라는 코드를 만나면 내부적으로 다음과 같은 과정을 거칩니다.

  1. 파싱(Parsing): | 뒤에 있는 단어(무언가)를 읽습니다.
  2. 조회(Lookup): 엔진 내부의 filters라는 딕셔너리에서 그 단어를 찾습니다.
    • 예: filters['length'], filters['upper'], filters['list']

 

4. 엔진별 SSTI 식별용(무해) 페이로드

  1. Jinja2(Flask): {{7*7}} → 49
  2. Twig(PHP): {{7*7}} → 49
  3. FreeMarker(Java): ${7*7} → 49
  4. Thymeleaf(Java): [[${7*7}]] → 설정에 따라 평가
  5. Smarty(PHP): {$smarty.version} → 버전 문자열
  6. Handlebars/Mustache: {{7*7}} → 보통 연산 미지원(그대로 출력될 수 있음)

'Security > 웹' 카테고리의 다른 글

Redis 취약점과 안전한 사용 방법  (0) 2026.05.07
모의해킹 방법론 OWASP WSTG  (0) 2026.04.21
취약점 점검 후기  (0) 2026.04.02
[WEB] wizmall로 Bug Bounty 실습해보기  (0) 2026.03.18
[web] NoSQL 인젝션(Injection)  (0) 2026.03.01
'Security/웹' 카테고리의 다른 글
  • 모의해킹 방법론 OWASP WSTG
  • 취약점 점검 후기
  • [WEB] wizmall로 Bug Bounty 실습해보기
  • [web] NoSQL 인젝션(Injection)
yt_5246
yt_5246
yt5246 님의 블로그 입니다.
  • yt_5246
    yt의 공부 블로그
    yt_5246
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
    • 분류 전체보기 (83) N
      • IT (1)
      • Security (22)
        • 시스템해킹 (3)
        • 리버싱 (8)
        • 암호학 (0)
        • 웹 (6)
        • tools (5)
      • Book (0)
      • 자격증 (5)
      • 워게임 (46)
        • DVWA (7)
        • WebGoat (4)
        • webhacking.kr (35)
      • 버그바운티 (1)
      • CTF (6)
  • 인기 글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.6
yt_5246
[web] SSTI 알아보기
상단으로

티스토리툴바