Dreamhack/Dreamhack Wargame (Challenge)

[47] IT 비전공자 [dreamhack]simple-ssti문제 풀기

imaginefuture-1 2024. 10. 26. 08:26

 

날씨가 겨울이 온게 실감난다. 다들 감기 조심하시길..

47번째 문제 가자~

오랜만에WEB이다

 

 

서버에 들어갔더니 SSTI홈페이지가 뜬다

 

익숙한..그 오류다 400번대 오류는 '클라이언트에 의한 에러가 있음'을 알려주는 상태코드다 404번은 요청 받은 자원을 찾을 수 없는 오류 메세지다 Not Found

 

오호? 에러메세지가 이런 모습이..? 이거이거..재밌는 문제겠군

 

지피티야지피티야 SSTL이 뭐야

 

GPT:

 

SSTI (Server-Side Template Injection) 취약점은 웹 애플리케이션에서 서버 측 템플릿 엔진을 사용할 때 발생할 수 있는 보안 취약점입니다. 이 취약점은 악의적인 사용자가 템플릿에 악성 코드를 주입하여 서버에서 실행할 수 있게 하는 공격입니다.

### SSTI 취약점의 작동 원리

1. **템플릿 엔진**: 많은 웹 프레임워크는 HTML을 동적으로 생성하기 위해 템플릿 엔진을 사용합니다. 이러한 엔진은 사용자가 제공한 데이터를 템플릿에 삽입하여 최종 HTML을 생성합니다.
 

 

사용자가 제공한데이터 -> 템플릿에 삽입 -> HTML 최종 생성

 

 
2. **사용자 입력 검증 부족**: 템플릿 엔진이 사용자 입력을 적절히 검증하지 않거나 필터링하지 않으면, 공격자는 템플릿에 악성 코드를 삽입할 수 있습니다.

 

(여기서 악성 코드 삽입)                                                           

사용자가 제공한데이터 -> 템플릿에 삽입 -> HTML 최종 생성



3. **코드 실행**: 공격자는 템플릿 코드에 주입된 악성 스크립트를 통해 서버에서 임의의 코드를 실행하거나, 민감한 데이터를 노출할 수 있습니다.

 

(여기서 악성 코드 삽입)                              (보안 이슈 발생)

사용자가 제공한데이터 -> 템플릿에 삽입 -> HTML 최종 생성




### 예시

가장 일반적인 예시는 Jinja2와 같은 템플릿 엔진을 사용하는 Flask 웹 애플리케이션입니다.

#### 취약한 코드 예시:

```python
from flask import Flask, request, render_template_string

app = Flask(__name__)

@app.route('/')
def index():
    user_input = request.args.get('name')
    template = f'Hello, {user_input}!'
    return render_template_string(template)

if __name__ == '__main__':
    app.run()
```

위의 코드에서 사용자가 URL 파라미터로 입력한 `name` 값이 직접 템플릿에 삽입됩니다. 만약 공격자가 다음과 같이 요청하면:

```
http://localhost:5000/?name={{ config }}
```

서버는 `config`라는 Jinja2의 내장 객체를 통해 서버의 설정 정보를 출력하게 됩니다. 이를 통해 공격자는 서버 정보를 노출할 수 있습니다.

### SSTI 공격의 결과

1. **정보 노출**: 서버의 민감한 정보(환경 변수, 데이터베이스 크레덴셜 등)가 노출될 수 있습니다.
2. **임의 코드 실행**: 공격자는 서버에서 임의의 코드를 실행할 수 있게 되어, 데이터 손상 또는 데이터 유출 등의 결과를 초래할 수 있습니다.
3. **서비스 거부**: 악의적인 코드를 통해 서버를 중단시키거나, 서비스 거부 공격을 감행할 수 있습니다.

### 방어 방법

1. **입력 검증**: 사용자 입력을 철저히 검증하고, 예상하지 않은 입력을 차단합니다.
2. **출력 인코딩**: 사용자 데이터를 템플릿에 삽입할 때, HTML 인코딩을 적용하여 악성 코드를 방지합니다.
3. **템플릿 엔진의 보안 기능 활용**: 템플릿 엔진의 보안 기능을 적극 활용하고, 민감한 정보가 노출되지 않도록 설정합니다.
4. **최소 권한 원칙**: 서버에서 실행되는 코드는 최소한의 권한만 가지도록 설정하여, 공격자가 시스템에 접근할 수 있는 경로를 줄입니다.

SSTI는 웹 애플리케이션에서 주의해야 할 중요한 취약점 중 하나입니다. 추가적으로 궁금한 점이 있거나 더 자세한 설명이 필요하시면 언제든지 말씀해 주세요!


 

소스코드를 보자!

 

 

#!/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 웹 애플리케이션의 간단한 구현을 보여줍니다. 이 코드를 분석하면 다음과 같은 주요 요소들이 있습니다:

### 1. **라이브러리 임포트**
- `Flask`: Flask 웹 프레임워크를 사용하여 웹 애플리케이션을 만들기 위해 임포트합니다.
- `request`, `render_template`, `render_template_string`, `make_response`, `redirect`, `url_for`: 다양한 Flask 기능을 사용하기 위해 임포트합니다.

### 2. **플라스크 앱 초기화**
```python
app = Flask(__name__)
```
- Flask 애플리케이션 객체를 생성합니다.

### 3. **FLAG 읽기**
```python
try:
    FLAG = open('./flag.txt', 'r').read()
except:
    FLAG = '[**FLAG**]'
```
- `flag.txt` 파일을 열어 내용을 읽고 `FLAG` 변수에 저장합니다. 파일을 찾지 못할 경우 기본값으로 `"[**FLAG**]"`를 사용합니다. 
- 이 `FLAG`는 이후 `app.secret_key`에 사용되어 세션을 보호하는 데 사용됩니다.

### 4. **라우트 정의**
```python
@app.route('/')
def index():
    return render_template('index.html')
```
- 웹 애플리케이션의 루트 URL(`/`)에 접근할 때 `index.html` 템플릿을 렌더링하여 반환합니다.

### 5. **404 오류 핸들러**
```python
@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
```
- 404 오류(페이지를 찾을 수 없음)가 발생할 경우, 사용자에게 사용자 정의 HTML 템플릿을 렌더링하여 반환합니다.
- 요청한 경로(`request.path`)를 포함하여 사용자에게 알려줍니다.

### 6. **앱 실행**
```python
app.run(host='0.0.0.0', port=8000)
```
- 애플리케이션을 실행하며, `0.0.0.0` 주소에서 8000 포트를 통해 요청을 수신합니다. 이는 모든 IP 주소에서 접근할 수 있도록 설정한 것입니다.

### **주요 특징 및 보안 고려사항**
1. **`secret_key` 설정**: Flask의 `secret_key`는 세션 관리 및 CSRF 보호와 같은 보안 기능에 사용됩니다. 이 코드에서는 `FLAG` 파일의 내용을 `secret_key`로 사용하므로, 만약 이 값이 유출된다면 세션 탈취와 같은 공격에 취약해질 수 있습니다.

2. **에러 처리**: 404 오류에 대한 사용자 정의 처리기를 제공하여, 일반적인 오류 페이지 대신 사용자 친화적인 메시지를 반환합니다. 이는 사용자의 경험을 개선할 수 있습니다.

3. **파일 입출력**: `flag.txt` 파일을 읽기 위한 접근이 있지만, 파일의 경로가 하드코딩되어 있어 해당 경로에 대한 권한이 없는 사용자에게는 취약할 수 있습니다. 만약 이 파일의 내용을 유출하려는 공격이 발생한다면, 이를 방지할 수 있는 조치가 필요합니다.

4. **코드 가독성**: 코드가 간결하게 작성되어 있으며, 필요한 부분에 대한 주석을 추가하면 더욱 이해하기 쉬운 코드가 될 것입니다.

이 코드에 대한 추가 질문이나 특정 부분에 대한 더 자세한 설명이 필요하다면 언제든지 말씀해 주세요!

 

3번이 취약점이며 이걸 이용해서 풀어야할 것 같다.


 

https://mokpo.tistory.com/121

 

[dreamhack] simple-ssti 문제풀이

[WEB] simple-ssti 문제풀이 SSTI(Server Side Template Injection) 취약점은 공격자가 서버 측의 기본 템플릿 구문을 이용하여 악성 페이로드를 삽입한 다음 서버 측에서 실행되면서 생기는 취약점이며 웹 템

mokpo.tistory.com

https://keyme2003.tistory.com/entry/dreamhack-simple-ssti

 

[dreamhack] simple-ssti

개념정리SSTI에 대한 개념을 간단하게 짚고 넘어가자. ○ SSTISSTI(Server Side Template Injection)취약점은 웹 어플리케이션에 적용된 웹 템플릿 엔진(Web Template Engine)에 공격자의 공격 코드가 템플릿에 포

keyme2003.tistory.com

KEYME 블로거분 글을 보면 보안 대응방안은 무엇이 좋은지 설명도 추가로 해놓으셨다! 나도 글에 이제 추가해야지!

 


SSTI가 발생하는 부분은 위와 같다.
 
요청 시, 전달 받은 request.path를 template에 넣어 render_template_string() 로 랜더링한다.
 
이 과정에서 request.path에 대한 검증을 수행하지 않고 render_template_string()을 사용하고 있으므로 {{}} 형태의 템플릿 코드를 입력한다면, 템플릿 코드가 실행되면서 서버 내부의 정보를 가져올 수 있다.
출처 ㅣ https://keyme2003.tistory.com/entry/dreamhack-simple-ssti

 

{{config.items()}} 명령어를 통해 현재 딕셔너리 형태로 설정되어 있는 config를 확인해보자.

출처: https://mokpo.tistory.com/121 [MSS:티스토리]

 

 

 

{{ config.items() }}는 일반적으로 Flask와 같은 웹 프레임워크에서 사용하는 템플릿 엔진인 Jinja2의 구문입니다. 이 구문은 config 객체의 모든 설정 항목을 템플릿에서 출력하기 위해 사용됩니다. 자세히 설명하자면:

1. config 객체

  • config는 Flask 애플리케이션에서 설정 정보를 저장하는 딕셔너리입니다. 이 객체는 애플리케이션의 설정값(예: 디버그 모드, 데이터베이스 URI 등)을 키-값 쌍으로 저장합니다.
  • app.config를 통해 접근할 수 있으며, 이는 Flask 애플리케이션을 구성하는 다양한 설정값을 포함합니다.

2. .items() 메서드

  • .items() 메서드는 Python의 딕셔너리에서 사용되는 메서드로, 딕셔너리의 모든 키-값 쌍을 튜플의 리스트 형태로 반환합니다. 예를 들어, config.items()는 config에 있는 모든 설정의 목록을 반환합니다.

3. Jinja2 템플릿에서의 사용

  • {{ ... }} 구문은 Jinja2에서 변수를 출력하는 방식입니다. 이 구문 안에 코드를 넣으면 해당 코드의 결과값이 HTML로 렌더링됩니다.

 


입력한 페이지  경로를 그대로 출력해주는 페이지에 {{config.items()}}  명령어를 입력하면

 

 

 

FLAG가 있다!