[๐Ÿ’  Platinum 4] 0์˜ ๋Ÿฐ๋ ์Šค๋ฅผ ๊ฐ๋งˆ ์ฝ”๋“œ๋กœ ๋˜๊ฐ๊ธฐ โ€” DreamHack Run ํ’€์ด

2026-08-18ยท1๋ถ„ ์ฝ๊ธฐยท

[๐Ÿ’  Platinum 4] 0์˜ ๋Ÿฐ๋ ์Šค๋ฅผ ๊ฐ๋งˆ ์ฝ”๋“œ๋กœ ๋˜๊ฐ๊ธฐ โ€” DreamHack Run ํ’€์ด

๋ฐฐํฌ ํŒŒ์ผ์€ 10KB ์งœ๋ฆฌ stripped ELF ์™€ 160KB ์งœ๋ฆฌ flag.enc ๋‘ ๊ฐœ๋ฟ์ด๋‹ค. ๋ฐ”์ด๋„ˆ๋ฆฌ๋Š” ๋ณตํ˜ธ๊ธฐ๊ฐ€ ์•„๋‹ˆ๋ผ ์ธ์ฝ”๋”์˜€๊ณ , 0 ์˜ ๋Ÿฐ๋ ์Šค๋ฅผ Elias ๊ฐ๋งˆ ์œ ์‚ฌ ์ฝ”๋“œ๋กœ ๋ฐ”๊ฟ” ์“ฐ๋Š” 1810๋ฐ”์ดํŠธ์งœ๋ฆฌ ๋ฃจํ‹ด ํ•˜๋‚˜๊ฐ€ ์ „๋ถ€์˜€๋‹ค. ๋ถ„๊ธฐ ํ•˜๋‚˜๋ฅผ ๋ฐ˜๋Œ€๋กœ ์ฝ์œผ๋ฉด ๋ณต์›๋ณธ์ด ํ†ต์งธ๋กœ ๋น„ํŠธ ๋ฐ˜์ „๋œ๋‹ค. objdump ๋กœ ์ธ์ฝ”๋”๋ฅผ ์ฝ๊ณ  gdb ๋กœ ๋ชป ๋ฐ•์€ ๋’ค ์—ญํ•จ์ˆ˜๋ฅผ ์จ์„œ 10000x10000 PNG ๋ฅผ ๋˜์‚ด๋ ธ๊ณ , ๋ณต์›๋ณธ์„ ๋ฌธ์ œ ๋ฐ”์ด๋„ˆ๋ฆฌ์— ์žฌํˆฌ์ž…ํ•ด sha256 ์ผ์น˜๋กœ ๊ฒ€์ฆํ–ˆ๋‹ค.

๋ฌธ์ œ: DreamHack โ€” Run ๋ถ„๋ฅ˜: reversing ๋‚œ์ด๋„: ๐Ÿ’  Platinum 4 FLAG: GoN{run_length_encoding}

๋ฌธ์ œ ์„ค๋ช…์€ ์ด๊ฒŒ ์ „๋ถ€๋‹ค.

Time is running out. There's nowhere to run. You need to run this program. So run. RUN. NOW

ํžŒํŠธ๋„ ์—†๊ณ , ์ฒจ๋ถ€๋œ BGM ๋งํฌ ํ•˜๋‚˜๊ฐ€ ๋ค์ด๋‹ค. 2022 Spring GoN Open Qual CTF ์—์„œ ๋„˜์–ด์˜จ ๋ฌธ์ œ๋ผ ํ”Œ๋ž˜๊ทธ ์ ‘๋‘์‚ฌ๋„ ๋“œ๋ฆผํ•ต ๊ด€๋ก€์ธ DH ๊ฐ€ ์•„๋‹ˆ๋ผ GoN ์ด๋‹ค. ์ด๊ฑธ ๋ชจ๋ฅด๊ณ  DH ๋กœ ์‹œ์ž‘ํ•˜๋Š” ๋ฌธ์ž์—ด๋งŒ ์ฐพ์œผ๋ฉด ๋๊นŒ์ง€ ์•„๋ฌด๊ฒƒ๋„ ๋ชป ์ฐพ๋Š”๋‹ค.

๋ฐ›์€ ๊ฑด ํŒŒ์ผ ๋‘ ๊ฐœ๋ฟ์ด๋‹ค.

file extracted/main extracted/flag.enc; ls -l extracted; readelf -h extracted/main | grep -E "Type|Entry|Machine"

file ๊ณผ readelf -h ๋กœ ๋ณธ ๋ฐฐํฌ ํŒŒ์ผ โ€” main ์€ 10,216๋ฐ”์ดํŠธ stripped PIE ELF ์ด๊ณ  flag.enc ๋Š” 160,672๋ฐ”์ดํŠธ๋‹ค. file ์ด flag.enc ๋ฅผ OpenPGP Public Key ๋ผ๊ณ  ๋ถ€๋ฅด๋Š” ๊ฑด ์ฒซ ๋ฐ”์ดํŠธ๊ฐ€ ์šฐ์—ฐํžˆ ๊ฒน์นœ ์˜คํƒ์ด๋‹ค
file ๊ณผ readelf -h ๋กœ ๋ณธ ๋ฐฐํฌ ํŒŒ์ผ โ€” main ์€ 10,216๋ฐ”์ดํŠธ stripped PIE ELF ์ด๊ณ  flag.enc ๋Š” 160,672๋ฐ”์ดํŠธ๋‹ค. file ์ด flag.enc ๋ฅผ OpenPGP Public Key ๋ผ๊ณ  ๋ถ€๋ฅด๋Š” ๊ฑด ์ฒซ ๋ฐ”์ดํŠธ๊ฐ€ ์šฐ์—ฐํžˆ ๊ฒน์นœ ์˜คํƒ์ด๋‹ค

flag.enc ๋ฅผ ๋‘๊ณ  file ์ด "OpenPGP Public Key" ๋ผ๊ณ  ๋‹ตํ•˜๋Š”๋ฐ, ์ด๊ฑด ์ฒซ ๋ฐ”์ดํŠธ ํ•˜๋‚˜๊ฐ€ ์šฐ์—ฐํžˆ ๊ฒน์ณ์„œ ๋‚˜์˜จ ์˜คํƒ์ด๋‹ค. ์‹ค์ œ๋กœ๋Š” PGP ์™€ ์•„๋ฌด ์ƒ๊ด€์ด ์—†๋‹ค. ์ด๋ฆ„์ด flag.enc ๋ผ๋Š” ๊ฒƒ, ๊ทธ๋ฆฌ๊ณ  ํ™•์žฅ์ž๊ฐ€ .enc ๋ผ๋Š” ๊ฒƒ๋งŒ ๋ถ™๋“ค๊ณ  ์‹œ์ž‘ํ•œ๋‹ค.


๋ฌธ์ œ ๊ฐœ์š”

ํ•ญ๋ชฉ๋‚ด์šฉ
๋ฌธ์ œ๋ช…Run (2022 Spring GoN Open Qual CTF ์ถœ์ œ์ž‘)
๋‚œ์ด๋„๐Ÿ’  Platinum 4
๋ถ„๋ฅ˜reversing
์ œ๊ณต ํŒŒ์ผmain (10,216 B ยท stripped PIE ELF64) ยท flag.enc (160,672 B)
์„œ๋ฒ„์—†์Œ (์˜คํ”„๋ผ์ธ ๋ฌธ์ œ)
์ŠคํƒC ยท glibc ์ €์ˆ˜์ค€ ์ž…์ถœ๋ ฅ(open/read/lseek/write)๋งŒ ์‚ฌ์šฉ
ํ•ต์‹ฌ ๊ธฐ๋ฒ•0 ์˜ ๋Ÿฐ๋ ์Šค๋ฅผ Elias ๊ฐ๋งˆ ์œ ์‚ฌ ์ฝ”๋“œ๋กœ ์ธ์ฝ”๋”ฉ, ๋ฐ”์ดํŠธ ์•ˆ์—์„œ LSB-first

ํ’€์ด ํ๋ฆ„์€ ์งง๋‹ค. main ์€ ๋ณตํ˜ธ๊ธฐ๊ฐ€ ์•„๋‹ˆ๋ผ ์ธ์ฝ”๋”๋‹ค. ์ธ์ž๋กœ ๋ฐ›์€ ํŒŒ์ผ์„ ํ†ต์งธ๋กœ ์ฝ์–ด <ํŒŒ์ผ์ด๋ฆ„>.enc ๋ฅผ ๋ฑ‰๋Š”๋‹ค. ๊ทธ๋Ÿฌ๋‹ˆ flag.enc ๋Š” flag ๋ผ๋Š” ํŒŒ์ผ์„ ์ด ํ”„๋กœ๊ทธ๋žจ์— ํ•œ ๋ฒˆ ํ†ต๊ณผ์‹œํ‚จ ๊ฒฐ๊ณผ๋ฌผ์ด๊ณ , ์šฐ๋ฆฌ๊ฐ€ ํ•  ์ผ์€ ์ด ์ธ์ฝ”๋”๋ฅผ ์ •ํ™•ํžˆ ์ฝ์–ด ์—ญํ•จ์ˆ˜๋ฅผ ์“ฐ๋Š” ๊ฒƒ์ด๋‹ค.

ํ•จ์ •์€ ๋”ฑ ํ•˜๋‚˜๋‹ค. ๋Ÿฐ์˜ ๋Œ€์ƒ์ด 1 ์ด ์•„๋‹ˆ๋ผ 0 ์ด๋ผ๋Š” ๊ฒƒ. ์ด ์กฐ๊ฑด ๋ถ„๊ธฐ ํ•œ ์ค„์„ ๋ฐ˜๋Œ€๋กœ ์ฝ์œผ๋ฉด ๋ณต์›์€ ๋๊นŒ์ง€ ๋ฉ€์ฉกํ•˜๊ฒŒ ๋Œ๋ฉด์„œ ๊ฒฐ๊ณผ๋งŒ ์ „ ๋น„ํŠธ ๋ฐ˜์ „๋ณธ์ด ๋œ๋‹ค.



๐Ÿงฉ ์ •์ฐฐ โ€” ์‹ฌ๋ณผ๋„ ๋ฌธ์ž์—ด๋„ ์—†๋Š” 10KB

stripped ๋ผ nm ์€ ์•„๋ฌด๊ฒƒ๋„ ๋ชป ์ค€๋‹ค. ๋Œ€์‹  ๋™์  ์‹ฌ๋ณผ ํ…Œ์ด๋ธ”์€ ๋‚จ์•„ ์žˆ๊ณ , ์—ฌ๊ธฐ๊ฐ€ ์ œ์ผ ๋งŽ์€ ๊ฑธ ๋งํ•ด ์ค€๋‹ค.

readelf --dyn-syms -W extracted/main

readelf --dyn-syms ๋กœ ๋ณธ .dynsym 18๊ฐœ โ€” free/write/strlen/lseek/close/read/malloc/realloc/open/sprintf/exit ๋งŒ ์žˆ๊ณ  fopen ์ด๋‚˜ printf ๊ฐ™์€ ํ‘œ์ค€ ์ŠคํŠธ๋ฆผ ๊ณ„์—ด ํ•จ์ˆ˜๋Š” ํ•˜๋‚˜๋„ ์—†๋‹ค
readelf --dyn-syms ๋กœ ๋ณธ .dynsym 18๊ฐœ โ€” free/write/strlen/lseek/close/read/malloc/realloc/open/sprintf/exit ๋งŒ ์žˆ๊ณ  fopen ์ด๋‚˜ printf ๊ฐ™์€ ํ‘œ์ค€ ์ŠคํŠธ๋ฆผ ๊ณ„์—ด ํ•จ์ˆ˜๋Š” ํ•˜๋‚˜๋„ ์—†๋‹ค

๊ฐ€์ ธ๋‹ค ์“ฐ๋Š” libc ํ•จ์ˆ˜๊ฐ€ ์—ด ๋ช‡ ๊ฐœ๋ฟ์ด๊ณ , ๊ทธ ์กฐํ•ฉ์ด ๋…ธ๊ณจ์ ์ด๋‹ค. open ยท lseek ยท read ยท write ยท close ๋กœ ํŒŒ์ผ์„ ์ง์ ‘ ๋‹ค๋ฃจ๊ณ , malloc ยท realloc ยท free ๋กœ ๋ฒ„ํผ๋ฅผ ๋Š˜๋ ธ๋‹ค ์ค„์ด๊ณ , sprintf ์™€ strlen ์œผ๋กœ ๋ฌธ์ž์—ด์„ ํ•˜๋‚˜ ๋งŒ๋“ ๋‹ค. fopen ๋„ printf ๋„ ์—†๋‹ค. ํ™”๋ฉด์— ๋ญ˜ ์ถœ๋ ฅํ•˜๋Š” ํ”„๋กœ๊ทธ๋žจ์ด ์•„๋‹ˆ๋ผ๋Š” ๋œป์ด๋‹ค.

๋ฌธ์ž์—ด ์ชฝ์€ ๋” ์•™์ƒํ•˜๋‹ค.

strings -a extracted/main | wc -l; strings -a extracted/main | grep -nE "enc|flag|GoN|%"

strings ๊ฒฐ๊ณผ 51์ค„ ์ค‘ ์˜๋ฏธ ์žˆ๋Š” ๋ฌธ์ž์—ด์€ 25๋ฒˆ์งธ %s.enc ํ•˜๋‚˜๋ฟ์ด๋‹ค. flag ๋‚˜ GoN ์œผ๋กœ ์‹œ์ž‘ํ•˜๋Š” ๋ฌธ์ž์—ด์€ ๋ฐ”์ด๋„ˆ๋ฆฌ ์•ˆ์— ์กด์žฌํ•˜์ง€ ์•Š๋Š”๋‹ค
strings ๊ฒฐ๊ณผ 51์ค„ ์ค‘ ์˜๋ฏธ ์žˆ๋Š” ๋ฌธ์ž์—ด์€ 25๋ฒˆ์งธ %s.enc ํ•˜๋‚˜๋ฟ์ด๋‹ค. flag ๋‚˜ GoN ์œผ๋กœ ์‹œ์ž‘ํ•˜๋Š” ๋ฌธ์ž์—ด์€ ๋ฐ”์ด๋„ˆ๋ฆฌ ์•ˆ์— ์กด์žฌํ•˜์ง€ ์•Š๋Š”๋‹ค

51์ค„์ด ๋‚˜์˜ค๋Š”๋ฐ ๋Œ€๋ถ€๋ถ„ ์„น์…˜ ์ด๋ฆ„์ด๊ณ , ์‚ฌ๋žŒ์ด ์“ด ๋ฌธ์ž์—ด์€ %s.enc ํ•˜๋‚˜๋‹ค. sprintf ์˜ ํฌ๋งท ๋ฌธ์ž์—ด์ด ๊ทธ๊ฒƒ ํ•˜๋‚˜๋ผ๋Š” ๋œป์ด๊ณ , ๊ทธ๋ ‡๋‹ค๋ฉด ๋งŒ๋“ค์–ด ๋‚ด๋Š” ํŒŒ์ผ ์ด๋ฆ„์€ ์ž…๋ ฅํŒŒ์ผ์ด๋ฆ„ + .enc ๋‹ค. flag.enc ๋ผ๋Š” ๋ฐฐํฌ ํŒŒ์ผ ์ด๋ฆ„์ด ๊ณง "์›๋ณธ์€ flag ์˜€๋‹ค" ๋Š” ์ฆ๊ฑฐ๊ฐ€ ๋œ๋‹ค.

ํ”Œ๋ž˜๊ทธ ๋ฌธ์ž์—ด ์ž์ฒด๋Š” ๋ฐ”์ด๋„ˆ๋ฆฌ ์–ด๋””์—๋„ ์—†๋‹ค. ์ด ๋ฌธ์ œ๋Š” ๊ฒ€์ฆ๊ธฐ๊ฐ€ ์•„๋‹ˆ๋ผ ๋ณ€ํ™˜๊ธฐ๋‹ค.



๐Ÿ”ฌ main() โ€” ํŒŒ์ผ์„ ํ†ต์งธ๋กœ ๋น„ํŠธ์ŠคํŠธ๋ฆผ์— ์–น๋Š”๋‹ค

.text ๋Š” 0x870 ๋ถ€ํ„ฐ 0xf82 ๊นŒ์ง€, 1810๋ฐ”์ดํŠธ๋‹ค. ํ•จ์ˆ˜๋Š” ์—ฌ๋Ÿ ๊ฐœ๊ณ  ๊ทธ์ค‘ ์ ˆ๋ฐ˜์ด ๋น„ํŠธ ํ•˜๋‚˜๋ฅผ ์ฝ๊ณ  ์“ฐ๋Š” ๋„์šฐ๋ฏธ๋‹ค. ์—”ํŠธ๋ฆฌ์—์„œ __libc_start_main ์— ๋„˜๊ธฐ๋Š” ์ฒซ ์ธ์ž๊ฐ€ 0xd87 ์ด๋ผ ๊ฑฐ๊ธฐ๊ฐ€ main ์ด๋‹ค.

์•ž๋ถ€๋ถ„์€ ํŒŒ์ผ์„ ์—ฌ๋Š” ๊ณณ์ด๋‹ค. ์ฃผ์„์€ ๋‚ด๊ฐ€ sed ๋กœ ์–น์€ ๊ฒƒ์ด๊ณ , ๋‚˜๋จธ์ง€๋Š” objdump ์›๋ฌธ ๊ทธ๋Œ€๋กœ๋‹ค.

objdump -d -M intel --no-show-raw-insn --start-address=0xda5 --stop-address=0xe24 extracted/main | sed -f annot_main.sed

objdump ๋กœ ๋ณธ main ์•ž๋ถ€๋ถ„ โ€” argc ๋ฅผ 2์™€ ๋น„๊ตํ•˜๊ณ  open ์œผ๋กœ argv[1] ์„ ์—ฐ ๋’ค 0xb8f ์˜ read_file ๋กœ ํ†ต์งธ๋กœ ์ฝ๊ณ  0xb2c ์˜ bs_init ์œผ๋กœ ์ถœ๋ ฅ ๋ฒ„ํผ๋ฅผ 4096๋ฐ”์ดํŠธ ์žก์€ ๋‹ค์Œ 0xc60 ์˜ encode ๋ฅผ ํ˜ธ์ถœํ•œ๋‹ค
objdump ๋กœ ๋ณธ main ์•ž๋ถ€๋ถ„ โ€” argc ๋ฅผ 2์™€ ๋น„๊ตํ•˜๊ณ  open ์œผ๋กœ argv[1] ์„ ์—ฐ ๋’ค 0xb8f ์˜ read_file ๋กœ ํ†ต์งธ๋กœ ์ฝ๊ณ  0xb2c ์˜ bs_init ์œผ๋กœ ์ถœ๋ ฅ ๋ฒ„ํผ๋ฅผ 4096๋ฐ”์ดํŠธ ์žก์€ ๋‹ค์Œ 0xc60 ์˜ encode ๋ฅผ ํ˜ธ์ถœํ•œ๋‹ค

์ธ์ž ๊ฐœ์ˆ˜๋ฅผ 2 ๋กœ ๋ชป ๋ฐ•๊ณ , argv[1] ์„ ์ฝ๊ธฐ ์ „์šฉ์œผ๋กœ ์—ฐ๋‹ค. ๊ทธ ๋‹ค์Œ์ด ์ด ๋ฌธ์ œ์˜ ๊ณจ๊ฒฉ์ด๋‹ค. read_file(&src, fd) ๋กœ ํŒŒ์ผ ์ „์ฒด๋ฅผ ํ•˜๋‚˜์˜ ๋น„ํŠธ์ŠคํŠธ๋ฆผ์— ๋‹ด๊ณ , bs_init(&dst, 0x1000) ์œผ๋กœ ์ถœ๋ ฅ์šฉ ๋น„ํŠธ์ŠคํŠธ๋ฆผ์„ 4KB ๋กœ ์žก๊ณ , encode(&src, &dst) ๋ฅผ ๋ถ€๋ฅธ๋‹ค.

๋’ท๋ถ€๋ถ„์€ ๊ฒฐ๊ณผ๋ฅผ ์“ฐ๋Š” ๊ณณ์ด๋‹ค.

objdump -d -M intel --no-show-raw-insn --start-address=0xe58 --stop-address=0xee5 extracted/main | sed -f annot_main.sed

objdump ๋กœ ๋ณธ main ๋’ท๋ถ€๋ถ„ โ€” sprintf ๋กœ ํ™•์žฅ์ž .enc ๋ฅผ ๋ถ™์ธ ๊ฒฝ๋กœ๋ฅผ ๋งŒ๋“ค๊ณ  open ์œผ๋กœ 0600 ๊ถŒํ•œ ํŒŒ์ผ์„ ๋งŒ๋“  ๋’ค write ๋กœ src ๊ตฌ์กฐ์ฒด์˜ ์˜คํ”„์…‹ 0x10 ์—์„œ 8๋ฐ”์ดํŠธ๋ฅผ ๋จผ์ € ์“ฐ๊ณ  0xc08 ์˜ flush ๋กœ ์ธ์ฝ”๋”ฉ ๋ณธ๋ฌธ์„ ์ด์–ด ์“ด๋‹ค
objdump ๋กœ ๋ณธ main ๋’ท๋ถ€๋ถ„ โ€” sprintf ๋กœ ํ™•์žฅ์ž .enc ๋ฅผ ๋ถ™์ธ ๊ฒฝ๋กœ๋ฅผ ๋งŒ๋“ค๊ณ  open ์œผ๋กœ 0600 ๊ถŒํ•œ ํŒŒ์ผ์„ ๋งŒ๋“  ๋’ค write ๋กœ src ๊ตฌ์กฐ์ฒด์˜ ์˜คํ”„์…‹ 0x10 ์—์„œ 8๋ฐ”์ดํŠธ๋ฅผ ๋จผ์ € ์“ฐ๊ณ  0xc08 ์˜ flush ๋กœ ์ธ์ฝ”๋”ฉ ๋ณธ๋ฌธ์„ ์ด์–ด ์“ด๋‹ค

0xead ์˜ lea rcx,[rax+0x10] ๊ณผ ๊ทธ ๋‹ค์Œ write(fd, rcx, 8) ์ด ์ค‘์š”ํ•˜๋‹ค. rax ๋Š” src ๊ตฌ์กฐ์ฒด์˜ ์ฃผ์†Œ๊ณ , ๊ฑฐ๊ธฐ์— 0x10 ์„ ๋”ํ•œ ์ž๋ฆฌ์—์„œ 8๋ฐ”์ดํŠธ๋ฅผ ๊ทธ๋Œ€๋กœ ์“ด๋‹ค. ์ถœ๋ ฅ ํŒŒ์ผ์˜ ์ฒซ 8๋ฐ”์ดํŠธ๋Š” ์ธ์ฝ”๋”ฉ ๊ฒฐ๊ณผ๊ฐ€ ์•„๋‹ˆ๋ผ src ๊ตฌ์กฐ์ฒด์˜ ์„ธ ๋ฒˆ์งธ ํ•„๋“œ๋ผ๋Š” ๋œป์ด๋‹ค. ๊ทธ๊ฒŒ ๋ญ”์ง€๋Š” ๊ณง ๋‚˜์˜จ๋‹ค.

์ „์ฒด๋ฅผ C ๋กœ ์˜ฎ๊ธฐ๋ฉด ์ด๋ ‡๋‹ค.

int main(int argc, char **argv) {
    BitStream src, dst;
    if (argc != 2) exit(1);
 
    int fd = open(argv[1], O_RDONLY);
    if (fd == -1) exit(1);
    read_file(&src, fd);                       /* ํŒŒ์ผ ์ „์ฒด -> src */
    close(fd);
 
    bs_init(&dst, 0x1000);                     /* ์ถœ๋ ฅ ๋ฒ„ํผ 4KB ๋กœ ์‹œ์ž‘ */
    encode(&src, &dst);
 
    char *path = malloc(strlen(argv[1]) + 5);  /* ".enc" + NUL */
    if (!path) exit(1);
    sprintf(path, "%s.enc", argv[1]);
 
    fd = open(path, O_CREAT | O_WRONLY, 0600);
    if (fd == -1) exit(1);
    write(fd, &src.cap, 8);                    /* ํ—ค๋” 8๋ฐ”์ดํŠธ */
    flush(&dst, fd);                           /* ์ธ์ฝ”๋”ฉ ๋ณธ๋ฌธ */
    close(fd);
    free(path);
    return 0;
}


๐Ÿงฑ ๋น„ํŠธ์ŠคํŠธ๋ฆผ โ€” ๊ตฌ์กฐ์ฒด ํ•˜๋‚˜์™€ ๋„์šฐ๋ฏธ ๋‹ค์„ฏ

0x97a ยท 0xaad ยท 0xb2c ยท 0xb8f ยท 0xc08 ๋‹ค์„ฏ ํ•จ์ˆ˜๊ฐ€ ์ „๋ถ€ ๊ฐ™์€ ๊ตฌ์กฐ์ฒด๋ฅผ ๋งŒ์ง„๋‹ค. ์˜คํ”„์…‹ 0 ์— ํฌ์ธํ„ฐ, 8 ์— ํ•˜๋‚˜, 0x10 ์— ํ•˜๋‚˜. ์“ฐ์ž„์ƒˆ๋ฅผ ๋ณด๋ฉด ์ •์ฒด๊ฐ€ ๋ฐ”๋กœ ๋‚˜์˜จ๋‹ค.

typedef struct {
    char  *buf;   /* +0x00 */
    size_t pos;   /* +0x08  ํ˜„์žฌ ์œ„์น˜ โ€” ๋ฐ”์ดํŠธ๊ฐ€ ์•„๋‹ˆ๋ผ ๋น„ํŠธ ๋‹จ์œ„ */
    size_t cap;   /* +0x10  ์šฉ๋Ÿ‰   โ€” ์—ญ์‹œ ๋น„ํŠธ ๋‹จ์œ„ */
} BitStream;

pos ๋ฅผ ์“ธ ๋•Œ๋งˆ๋‹ค shr rax,0x3 ๋กœ 8 ์„ ๋‚˜๋ˆ  ๋ฒ„ํผ ์ธ๋ฑ์Šค๋ฅผ ๋งŒ๋“ค๊ณ  and edx,0x7 ๋กœ ๋‚˜๋จธ์ง€๋ฅผ ๋น„ํŠธ ์œ„์น˜๋กœ ์“ด๋‹ค. ๊ทธ๋ž˜์„œ ๋‘˜ ๋‹ค ๋น„ํŠธ ๋‹จ์œ„๋‹ค. ๋„์šฐ๋ฏธ ๋‹ค์„ฏ์€ ์ด๋ ‡๊ฒŒ ๋™์ž‘ํ•œ๋‹ค.

void bs_init(BitStream *bs, size_t n) {        /* 0xb2c */
    if (n > 0x1fffffffffffffff) exit(1);
    bs->buf = malloc(n);
    bs->cap = n * 8;                           /* n ๋ฐ”์ดํŠธ = n*8 ๋น„ํŠธ */
    bs->pos = 0;
}
 
void read_file(BitStream *bs, int fd) {        /* 0xb8f */
    size_t sz = lseek(fd, 0, SEEK_END);
    bs_init(bs, sz);
    lseek(fd, 0, SEEK_SET);
    if (read(fd, bs->buf, sz) != sz) exit(1);
}
 
void put_bit(BitStream *bs, int b) {           /* 0x97a */
    if (bs->pos >= bs->cap) {
        bs->cap *= 2;
        bs->buf = realloc(bs->buf, bs->cap);   /* ๋น„ํŠธ ์ˆ˜๋ฅผ ๋ฐ”์ดํŠธ ์ˆ˜๋กœ ๋„˜๊ธด๋‹ค */
        if (!bs->buf) exit(1);
    }
    bs->buf[bs->pos >> 3] &= ~(1 << (bs->pos & 7));
    bs->buf[bs->pos >> 3] |= (b != 0) << (bs->pos & 7);
    bs->pos++;
}
 
int get_bit(BitStream *bs) {                   /* 0xaad */
    if (bs->pos >= bs->cap) exit(1);
    return (bs->buf[bs->pos >> 3] >> (bs->pos++ & 7)) & 1;
}
 
void flush(BitStream *bs, int fd) {            /* 0xc08 */
    while (bs->pos & 7) put_bit(bs, 1);        /* ๋‚จ๋Š” ์ž๋ฆฌ๋Š” 1 ๋กœ ์ฑ„์šด๋‹ค */
    write(fd, bs->buf, bs->pos >> 3);
}

์—ฌ๊ธฐ์„œ ์—ญํ•จ์ˆ˜์— ํ•„์š”ํ•œ ๊ทœ์น™ ๋‘ ๊ฐœ๊ฐ€ ํ™•์ •๋œ๋‹ค.

๋น„ํŠธ ์ˆœ์„œ๋Š” ๋ฐ”์ดํŠธ ์•ˆ์—์„œ LSB-first๋‹ค. 1 << (pos & 7) ์ด๋ผ pos ๊ฐ€ 0 ์ผ ๋•Œ ์ตœํ•˜์œ„ ๋น„ํŠธ๋ฅผ ๊ฑด๋“œ๋ฆฐ๋‹ค. ํ”ํžˆ ์“ฐ๋Š” MSB-first ๋กœ ์ฝ์œผ๋ฉด ์ฒซ ์ฝ”๋“œ์›Œ๋“œ๋ถ€ํ„ฐ ์–ด๊ธ‹๋‚œ๋‹ค.

๊ผฌ๋ฆฌ ํŒจ๋”ฉ์€ 1 ์ด๋‹ค. flush ๊ฐ€ ๋ฐ”์ดํŠธ ๊ฒฝ๊ณ„๋ฅผ ๋งž์ถ”๋ ค๊ณ  ์ฑ„์šฐ๋Š” ๊ฐ’์ด 1 ์ด๋ผ, ๋””์ฝ”๋”๊ฐ€ ํŒŒ์ผ ๋์—์„œ ์“ฐ๋ ˆ๊ธฐ ์ฝ”๋“œ์›Œ๋“œ๋ฅผ ๋ช‡ ๊ฐœ ๋” ์ฝ์„ ์ˆ˜ ์žˆ๋‹ค. ์›๋ณธ ๊ธธ์ด๋ฅผ ์•Œ๊ณ  ๊ฑฐ๊ธฐ์„œ ๋Š์–ด์•ผ ํ•˜๋Š” ์ด์œ ๋‹ค.

put_bit ์˜ realloc(bs->buf, bs->cap) ์€ ๋น„ํŠธ ์ˆ˜๋ฅผ ๋ฐ”์ดํŠธ ์ˆ˜ ์ž๋ฆฌ์— ๋„˜๊ธฐ๋Š” ์ฝ”๋“œ๋‹ค. 8๋ฐฐ๋กœ ๋„‰๋„‰ํžˆ ์žกํžˆ๋‹ˆ ๋™์ž‘์—๋Š” ๋ฌธ์ œ๊ฐ€ ์—†๊ณ , ์ธ์ฝ”๋”๊ฐ€ ์†์œผ๋กœ ์“ด ์ฝ”๋“œ๋ผ๋Š” ํ”์  ์ •๋„๋กœ ๋ณด๋ฉด ๋œ๋‹ค.


๐Ÿ’ฃ ํ•ต์‹ฌ โ€” encode() ๊ฐ€ ์„ธ๋Š” ๊ฒƒ์€ 1 ์ด ์•„๋‹ˆ๋ผ 0 ์ด๋‹ค

์ด์ œ 0xc60 ์ด๋‹ค. ์ด ํ•จ์ˆ˜๋งŒ ์ •ํ™•ํžˆ ์ฝ์œผ๋ฉด ๋ฌธ์ œ๊ฐ€ ๋๋‚œ๋‹ค.

objdump -d -M intel --no-show-raw-insn --start-address=0xc60 --stop-address=0xcdb extracted/main | sed -f annot_encode.sed

objdump ๋กœ ๋ณธ encode ์•ž๋ถ€๋ถ„ โ€” 0xca4 ์—์„œ get_bit ๋ฅผ ๋ถ€๋ฅด๊ณ  0xca9 ์˜ test eax,eax ๋‹ค์Œ 0xcab ์˜ je ๊ฐ€ ๊ฒฐ๊ณผ๊ฐ€ 0 ์ผ ๋•Œ 0xc7f ๋กœ ๋›ด๋‹ค. ๊ทธ 0xc7f ๊ฐ€ count ๋ฅผ ์˜ฌ๋ฆฌ๋Š” ์ž๋ฆฌ๋ผ ์„ธ๋Š” ๋Œ€์ƒ์€ 1 ์ด ์•„๋‹ˆ๋ผ 0 ์ด๋‹ค
objdump ๋กœ ๋ณธ encode ์•ž๋ถ€๋ถ„ โ€” 0xca4 ์—์„œ get_bit ๋ฅผ ๋ถ€๋ฅด๊ณ  0xca9 ์˜ test eax,eax ๋‹ค์Œ 0xcab ์˜ je ๊ฐ€ ๊ฒฐ๊ณผ๊ฐ€ 0 ์ผ ๋•Œ 0xc7f ๋กœ ๋›ด๋‹ค. ๊ทธ 0xc7f ๊ฐ€ count ๋ฅผ ์˜ฌ๋ฆฌ๋Š” ์ž๋ฆฌ๋ผ ์„ธ๋Š” ๋Œ€์ƒ์€ 1 ์ด ์•„๋‹ˆ๋ผ 0 ์ด๋‹ค

0xca4 ์—์„œ get_bit(src) ๋ฅผ ๋ถ€๋ฅธ๋‹ค. ๊ทธ ๋‹ค์Œ ๋‘ ์ค„์ด ์ด ๋ฌธ์ œ์˜ ์ „๋ถ€๋‹ค.

ca9:   test   eax,eax          ; ๋ฐฉ๊ธˆ ์ฝ์€ ๋น„ํŠธ
cab:   je     c7f              ; 0 ์ด๋ฉด c7f ๋กœ -- c7f ๋Š” count++ ํ•˜๋Š” ์ž๋ฆฌ๋‹ค

je ๋Š” "๊ฐ™์œผ๋ฉด" ์ด๊ณ  ๋น„๊ต ๋Œ€์ƒ์€ 0 ์ด๋‹ค. ์ฆ‰ ์ฝ์€ ๋น„ํŠธ๊ฐ€ 0 ์ผ ๋•Œ ์„ธ๋Ÿฌ ๊ฐ„๋‹ค. jne ์˜€๋‹ค๋ฉด 1 ์„ ์„ธ๋Š” ๊ฒƒ์ด๊ณ , ๊ธ€์ž ํ•˜๋‚˜ ์ฐจ์ด๋‹ค. ๊ทธ๋ฆฌ๊ณ  ์ด ํ•œ ๊ธ€์ž๊ฐ€ ๋ณต์›๋ณธ ์ „์ฒด์˜ ๊ทน์„ฑ์„ ๋’ค์ง‘๋Š”๋‹ค.

0xc7f ๋Š” count++ ํ•˜๊ธฐ ์ „์— src->pos < src->cap ์„ ํ•œ ๋ฒˆ ๋” ๋ณธ๋‹ค. 0 ์„ ์ฝ์—ˆ๋Š”๋ฐ ์ŠคํŠธ๋ฆผ์ด ๋ฐ”๋‹ฅ๋‚˜๋ฉด ๊ทธ ๋Ÿฐ์€ ํ†ต์งธ๋กœ ๋ฒ„๋ฆฌ๊ณ  ํ•จ์ˆ˜๊ฐ€ ๋๋‚œ๋‹ค. ํŒŒ์ผ ๋งจ ๋์˜ ์ž˜๋ฆฐ ๋Ÿฐ์€ ์ถœ๋ ฅ์— ์•ˆ ์‹ค๋ฆฐ๋‹ค๋Š” ๋œป์ด๋‹ค.

count ๊ฐ€ ์ •ํ•ด์ง€๋ฉด ๋’ท๋ถ€๋ถ„์ด ๊ทธ๊ฑธ ๋น„ํŠธ๋กœ ํŽธ๋‹ค.

objdump -d -M intel --no-show-raw-insn --start-address=0xcdb --stop-address=0xd6a extracted/main | sed -f annot_encode.sed

objdump ๋กœ ๋ณธ encode ๋’ท๋ถ€๋ถ„ โ€” bsr ๊ณผ xor 0x3f ๋กœ clz ๋ฅผ ๋งŒ๋“ค๊ณ  0x40 ์—์„œ ๋นผ nbits ๋ฅผ ๊ตฌํ•œ ๋’ค put_bit ๋กœ 1 ์„ nbits-1 ๋ฒˆ ๋‚ด๋ณด๋‚ด๊ณ  0 ํ•˜๋‚˜๋กœ ๋Š์€ ๋‹ค์Œ count ๋ฅผ shr ๋กœ ๋ฐ€์–ด ๊ฐ€๋ฉฐ LSB-first ๋กœ nbits ๋น„ํŠธ๋ฅผ ์“ด๋‹ค
objdump ๋กœ ๋ณธ encode ๋’ท๋ถ€๋ถ„ โ€” bsr ๊ณผ xor 0x3f ๋กœ clz ๋ฅผ ๋งŒ๋“ค๊ณ  0x40 ์—์„œ ๋นผ nbits ๋ฅผ ๊ตฌํ•œ ๋’ค put_bit ๋กœ 1 ์„ nbits-1 ๋ฒˆ ๋‚ด๋ณด๋‚ด๊ณ  0 ํ•˜๋‚˜๋กœ ๋Š์€ ๋‹ค์Œ count ๋ฅผ shr ๋กœ ๋ฐ€์–ด ๊ฐ€๋ฉฐ LSB-first ๋กœ nbits ๋น„ํŠธ๋ฅผ ์“ด๋‹ค

bsr rax, count ๊ฐ€ ์ตœ์ƒ์œ„ 1 ๋น„ํŠธ์˜ ์œ„์น˜๋ฅผ ์ฃผ๊ณ , xor rax, 0x3f ๊ฐ€ ๊ทธ๊ฑธ 63 ์—์„œ ๋นผ์„œ clz ๋กœ ๋ฐ”๊พผ๋‹ค. 0x40 - clz ๋Š” ๊ณง count ์˜ ๋น„ํŠธ๊ธธ์ด๋‹ค. ์ปดํŒŒ์ผ๋Ÿฌ๊ฐ€ __builtin_clzll ์„ ํŽธ ๋ชจ์–‘ ๊ทธ๋Œ€๋กœ๋‹ค.

void encode(BitStream *src, BitStream *dst) {
    while (src->pos < src->cap) {
        size_t count = 0;
        while (get_bit(src) == 0) {                    /* 0 ์„ ์„ผ๋‹ค */
            if (src->pos >= src->cap) return;
            count++;
        }
        if (count == 0) { put_bit(dst, 0); put_bit(dst, 0); continue; }
 
        size_t nbits = 64 - __builtin_clzll(count);    /* count ์˜ ๋น„ํŠธ๊ธธ์ด */
        for (int i = 0; i < nbits - 1; i++) put_bit(dst, 1);
        put_bit(dst, 0);
        for (int j = 0; j < nbits; j++) { put_bit(dst, count & 1); count >>= 1; }
    }
}

์›๋ณธ ๋น„ํŠธ์—ด์„ "0 ์ด ๋ช‡ ๊ฐœ ์ด์–ด์ง€๋‹ค 1 ๋กœ ๋๋‚˜๋Š” ๋Ÿฐ" ์˜ ๋‚˜์—ด๋กœ ๋ณด๊ณ , ๊ทธ ๋Ÿฐ์˜ ๊ธธ์ด๋งŒ ์ ๋Š” ๊ตฌ์กฐ๋‹ค. ๊ธธ์ด๋ฅผ ์ ๋Š” ๋ฐฉ์‹์€ Elias ๊ฐ๋งˆ ์ฝ”๋“œ์™€ ๊ฐ™์€ ๊ผด์ด๋‹ค. ์•ž์— 1 ์„ nbits-1 ๊ฐœ ๋ถ™์—ฌ ๊ธธ์ด๋ฅผ ์•Œ๋ฆฌ๊ณ , 0 ํ•˜๋‚˜๋กœ ๋Š๊ณ , ๊ฐ’์„ nbits ๋น„ํŠธ๋กœ ์ ๋Š”๋‹ค. ๋‹ค๋งŒ ๊ฐ’ ๋ถ€๋ถ„์ด ๊ต๊ณผ์„œ์ฒ˜๋Ÿผ MSB-first ๊ฐ€ ์•„๋‹ˆ๋ผ LSB-first ๋‹ค. put_bit(dst, count & 1) ๋‹ค์Œ์— count >>= 1 ์ด๋‹ˆ ์ตœํ•˜์œ„ ๋น„ํŠธ๊ฐ€ ๋จผ์ € ๋‚˜๊ฐ„๋‹ค.

๋Ÿฐ๋ ์Šค ์ฝ”๋“œ์›Œ๋“œ ๋„์‹ โ€” 0 ์ด ์—ฌ์„ฏ ๊ฐœ ์ด์–ด์ง€๋‹ค 1 ๋กœ ๋๋‚˜๋Š” ๋Ÿฐ์€ count ๊ฐ€ 6 ์ด๊ณ  nbits ๊ฐ€ 3 ์ด๋ผ 1 ์„ ๋‘ ๊ฐœ ๋‚ด๋ณด๋‚ธ ๋’ค 0 ์œผ๋กœ ๋Š๊ณ  6 ์„ LSB-first ์„ธ ๋น„ํŠธ๋กœ ์ ์–ด 110011 ์ด ๋œ๋‹ค
๋Ÿฐ๋ ์Šค ์ฝ”๋“œ์›Œ๋“œ ๋„์‹ โ€” 0 ์ด ์—ฌ์„ฏ ๊ฐœ ์ด์–ด์ง€๋‹ค 1 ๋กœ ๋๋‚˜๋Š” ๋Ÿฐ์€ count ๊ฐ€ 6 ์ด๊ณ  nbits ๊ฐ€ 3 ์ด๋ผ 1 ์„ ๋‘ ๊ฐœ ๋‚ด๋ณด๋‚ธ ๋’ค 0 ์œผ๋กœ ๋Š๊ณ  6 ์„ LSB-first ์„ธ ๋น„ํŠธ๋กœ ์ ์–ด 110011 ์ด ๋œ๋‹ค

count == 0 ์€ ํŠน์ˆ˜ ์ผ€์ด์Šค์ฒ˜๋Ÿผ ๋ณด์ด์ง€๋งŒ ๊ทœ์น™์ด ๊ฐ™๋‹ค. nbits ๊ฐ€ 1 ์ด๋ผ ์œ ๋„ˆ๋ฆฌ ๋ถ€๋ถ„์ด ๋น„๊ณ  ๊ฐ’ ๋น„ํŠธ ํ•˜๋‚˜(0)๋งŒ ๋‚จ์•„์„œ 0 0 ๋‘ ๋น„ํŠธ๊ฐ€ ๋œ๋‹ค. ๋””์ฝ”๋”์—์„œ ๋”ฐ๋กœ ๋ถ„๊ธฐํ•  ํ•„์š”๊ฐ€ ์—†๋‹ค.

๋””์ฝ”๋” ์ž…์žฅ์—์„œ ์ •๋ฆฌํ•˜๋ฉด ์ด๋ ‡๋‹ค.

์ฝ๋Š” ์ˆœ์„œํ•˜๋Š” ์ผ
10 ์„ ๋งŒ๋‚  ๋•Œ๊นŒ์ง€ 1 ์„ ์„ผ๋‹ค. ์„ผ ๊ฐœ์ˆ˜๋ฅผ k ๋ผ ํ•˜๋ฉด nbits = k + 1
2๊ทธ ๋’ค๋กœ nbits ๋น„ํŠธ๋ฅผ LSB-first ๋กœ ์ฝ์–ด count ๋ฅผ ๋งŒ๋“ ๋‹ค
30 ์„ count ๊ฐœ, ๊ทธ๋ฆฌ๊ณ  1 ์„ ํ•˜๋‚˜ ๋ฑ‰๋Š”๋‹ค
4์›๋ณธ ๋น„ํŠธ ์ˆ˜๋ฅผ ์ฑ„์šธ ๋•Œ๊นŒ์ง€ ๋ฐ˜๋ณต


๐Ÿงช ์ •์  ๋ถ„์„์„ ๋Ÿฐํƒ€์ž„์œผ๋กœ ๋ชป ๋ฐ•๊ธฐ

์ฝ์€ ๊ฒŒ ๋งž๋Š”์ง€ ์‹ค์ œ๋กœ ๋Œ๋ ค์„œ ํ™•์ธํ•œ๋‹ค. PIE ๋ผ ์ฃผ์†Œ๊ฐ€ ๋งค๋ฒˆ ๋‹ฌ๋ผ์ง€๋Š”๋ฐ, ์—ฌ๊ธฐ์„œ ๋ฒ ์ด์Šค๋ฅผ ๊ด€๋ก€๋กœ ๊ฐ€์ •ํ•˜๋ฉด ์•ˆ ๋œ๋‹ค. info proc mappings ์—์„œ ์‹ค์ œ ๋งคํ•‘์„ ์ฝ์–ด ์“ด๋‹ค.

set confirm off
set pagination off
starti
python
import gdb
base = None
for line in gdb.execute("info proc mappings", to_string=True).splitlines():
    if line.rstrip().endswith("/main"):        # PIE ๋ฒ ์ด์Šค๋Š” ๊ฐ€์ •ํ•˜์ง€ ์•Š๊ณ  ๋งคํ•‘์—์„œ ์ฝ๋Š”๋‹ค
        base = int(line.split()[0], 16)
        break
gdb.execute("set $base = %#x" % base)
print("PIE base            = %#x" % base)
end
break *($base + 0xc60)
break *($base + 0xcdb)
continue
printf "encode(src=%p, dst=%p)\n", $rdi, $rsi
printf "  src->buf          = %p\n", *(long *)$rdi
printf "  src->pos          = %ld\n", *(long *)($rdi + 8)
printf "  src->cap          = %ld bits = %ld B\n", *(long *)($rdi + 16), *(long *)($rdi + 16) / 8
printf "  src->buf[0..3]    = %02x %02x %02x %02x\n", *(unsigned char *)(*(long *)$rdi), *(unsigned char *)(*(long *)$rdi + 1), *(unsigned char *)(*(long *)$rdi + 2), *(unsigned char *)(*(long *)$rdi + 3)
continue
printf "count != 0 ์ธ ์ฒซ ์ฝ”๋“œ์›Œ๋“œ (0xcdb)\n"
printf "  count             = %ld\n", *(long *)($rbp - 0x10)
printf "  src->pos          = %ld  (์†Œ๋น„ํ•œ ์›๋ณธ ๋น„ํŠธ)\n", *(long *)(*(long *)($rbp - 0x28) + 8)
printf "  dst->pos          = %ld  (๋ฑ‰์€ ์ถœ๋ ฅ ๋น„ํŠธ)\n", *(long *)(*(long *)($rbp - 0x30) + 8)
kill
gdb -q -batch -x cmds.gdb --args extracted/main flag.png

gdb ๋ฐฐ์น˜ ์‹คํ–‰ ๊ฒฐ๊ณผ โ€” PIE ๋ฒ ์ด์Šค๋ฅผ ๋งคํ•‘์—์„œ ์ฝ์–ด encode ์— ๋ธŒ๋ ˆ์ดํฌ๋ฅผ ๊ฑธ์—ˆ๊ณ  src->cap ์ด 3928984๋น„ํŠธ ์ฆ‰ 491123๋ฐ”์ดํŠธ, src->buf ์•ž ๋„ค ๋ฐ”์ดํŠธ๊ฐ€ 89 50 4e 47 ๋กœ PNG ๋งค์ง์ด๋‹ค
gdb ๋ฐฐ์น˜ ์‹คํ–‰ ๊ฒฐ๊ณผ โ€” PIE ๋ฒ ์ด์Šค๋ฅผ ๋งคํ•‘์—์„œ ์ฝ์–ด encode ์— ๋ธŒ๋ ˆ์ดํฌ๋ฅผ ๊ฑธ์—ˆ๊ณ  src->cap ์ด 3928984๋น„ํŠธ ์ฆ‰ 491123๋ฐ”์ดํŠธ, src->buf ์•ž ๋„ค ๋ฐ”์ดํŠธ๊ฐ€ 89 50 4e 47 ๋กœ PNG ๋งค์ง์ด๋‹ค

์„ธ ๊ฐ€์ง€๊ฐ€ ํ•œ ๋ฒˆ์— ํ™•์ธ๋œ๋‹ค.

src->cap ์ด 3,928,984 ๋น„ํŠธ, ๋‚˜๋ˆ„๋ฉด 491,123 ๋ฐ”์ดํŠธ๋‹ค. ๊ตฌ์กฐ์ฒด ์„ธ ๋ฒˆ์งธ ํ•„๋“œ๊ฐ€ ์›๋ณธ ํŒŒ์ผ ํฌ๊ธฐ๋ผ๋Š” ์ถ”๋ก ์ด ๋งž์•˜๋‹ค. ๊ทธ๋ฆฌ๊ณ  main ์ด ์ถœ๋ ฅ ํŒŒ์ผ ๋งจ ์•ž์— ์“ฐ๋Š” 8๋ฐ”์ดํŠธ๊ฐ€ ๋ฐ”๋กœ ์ด ๊ฐ’์ด๋‹ค.

src->buf[0..3] ์ด 89 50 4e 47 ์ด๋‹ค. ์›๋ณธ์ด PNG ์˜€๋‹ค๋Š” ์‚ฌ์‹ค์ด ์ธ์ฝ”๋”ฉ ์ „ ๋‹จ๊ณ„์—์„œ ์ด๋ฏธ ๋“œ๋Ÿฌ๋‚œ๋‹ค. ๋ณต์› ๊ฒฐ๊ณผ๊ฐ€ PNG ๊ฐ€ ์•„๋‹ˆ๋ฉด ๋‚ด๊ฐ€ ํ‹€๋ฆฐ ๊ฒƒ์ด๋ผ๋Š” ๊ธฐ์ค€์„ ์ด ์—ฌ๊ธฐ์„œ ์ƒ๊ธด๋‹ค.

์ฒซ ์ฝ”๋“œ์›Œ๋“œ์—์„œ count = 2, src->pos = 4, dst->pos = 2 ๋‹ค. ์†์œผ๋กœ ๋งž์ถฐ ๋ณด๋ฉด 0x89 ๋Š” LSB-first ๋กœ 1 0 0 1 0 0 0 1 ์ด๋‹ค. ์ฒซ ๋น„ํŠธ๊ฐ€ 1 ์ด๋ผ ์ฒซ ๋Ÿฐ์€ count = 0 ์ด๊ณ  0 0 ๋‘ ๋น„ํŠธ๊ฐ€ ๋‚˜๊ฐ„๋‹ค(dst->pos = 2). ๊ทธ ๋‹ค์Œ 0 ์„ ๋‘ ๊ฐœ ์„ธ๊ณ  1 ์„ ๋งŒ๋‚˜ ๋ฉˆ์ถ”๋‹ˆ count = 2, src->pos = 4. ์ˆซ์ž๊ฐ€ ๊ทธ๋Œ€๋กœ ๋งž๋Š”๋‹ค.


๐Ÿ”Ž ํ—ค๋” 8๋ฐ”์ดํŠธ๋ถ€ํ„ฐ ์ฝ์–ด ๋ณธ๋‹ค

๋ฐ”์ด๋„ˆ๋ฆฌ ์ชฝ ๋ถ„์„์ด ๋๋‚ฌ์œผ๋‹ˆ ์ด์ œ flag.enc ๋ฅผ ์ง์ ‘ ๋ณธ๋‹ค.

#!/usr/bin/env python3
"""flag.enc ์•ž 8๋ฐ”์ดํŠธ(= ์ธ์ฝ”๋”๊ฐ€ ์จ ๋„ฃ์€ src->cap)๋ฅผ ์ฝ์–ด ์›๋ณธ ํฌ๊ธฐ๋ฅผ ์—ญ์‚ฐํ•œ๋‹ค."""
import sys
 
blob = open(sys.argv[1], 'rb').read()
n_bits = int.from_bytes(blob[:8], 'little')
print(f'ํŒŒ์ผ ์ „์ฒด      : {len(blob)} B')
print(f'ํ—ค๋” 8๋ฐ”์ดํŠธ   : {blob[:8].hex(" ")}')
print(f'-> src->cap    : {n_bits} bits = {n_bits // 8} B  (์›๋ณธ ํŒŒ์ผ ํฌ๊ธฐ)')
print(f'์ธ์ฝ”๋”ฉ ๋ณธ๋ฌธ    : {len(blob) - 8} B')
print(f'๋น„์œจ           : {(len(blob) - 8) / (n_bits // 8):.3f} ๋ฐฐ  (๋Š˜์–ด๋‚œ ๊ฒŒ ์•„๋‹ˆ๋ผ ์ค„์—ˆ๋‹ค)')
print(f'๋ณธ๋ฌธ ์ฒซ 4๋ฐ”์ดํŠธ: {blob[8:12].hex(" ")}')
bits = ''.join(f'{blob[8 + i]:08b}'[::-1] for i in range(3))   # ๋ฐ”์ดํŠธ ์•ˆ์—์„œ LSB-first
print(f'-> ๋น„ํŠธ์—ด(LSB-first) : {bits}')
python3 read_header.py extracted/flag.enc

read_header.py ์‹คํ–‰ ๊ฒฐ๊ณผ โ€” ํ—ค๋” 8๋ฐ”์ดํŠธ๊ฐ€ 98 f3 3b 00 00 00 00 00 ์ด๋ผ ์›๋ณธ์€ 3928984๋น„ํŠธ ์ฆ‰ 491123๋ฐ”์ดํŠธ์ด๊ณ  ์ธ์ฝ”๋”ฉ ๋ณธ๋ฌธ์€ 160664๋ฐ”์ดํŠธ๋กœ 0.327๋ฐฐ๋กœ ์ค„์—ˆ์œผ๋ฉฐ ๋ณธ๋ฌธ ์ฒซ ์„ธ ๋ฐ”์ดํŠธ๋ฅผ LSB-first ๋กœ ํŽด๋ฉด 001001101111000101100100 ์ด๋‹ค
read_header.py ์‹คํ–‰ ๊ฒฐ๊ณผ โ€” ํ—ค๋” 8๋ฐ”์ดํŠธ๊ฐ€ 98 f3 3b 00 00 00 00 00 ์ด๋ผ ์›๋ณธ์€ 3928984๋น„ํŠธ ์ฆ‰ 491123๋ฐ”์ดํŠธ์ด๊ณ  ์ธ์ฝ”๋”ฉ ๋ณธ๋ฌธ์€ 160664๋ฐ”์ดํŠธ๋กœ 0.327๋ฐฐ๋กœ ์ค„์—ˆ์œผ๋ฉฐ ๋ณธ๋ฌธ ์ฒซ ์„ธ ๋ฐ”์ดํŠธ๋ฅผ LSB-first ๋กœ ํŽด๋ฉด 001001101111000101100100 ์ด๋‹ค

ํ—ค๋”๊ฐ€ gdb ๋กœ ๋ณธ src->cap ๊ณผ ์ •ํ™•ํžˆ ๊ฐ™๋‹ค. ์›๋ณธ์€ 491,123 ๋ฐ”์ดํŠธ๋‹ค.

๋ˆˆ์— ๋„๋Š” ๊ฑด ํฌ๊ธฐ๋‹ค. ์ธ์ฝ”๋”ฉ ๋ณธ๋ฌธ์ด 160,664 ๋ฐ”์ดํŠธ๋ผ ์›๋ณธ์˜ 0.327 ๋ฐฐ๋‹ค. ๋Ÿฐ๋ ์Šค ์ธ์ฝ”๋”ฉ์€ ๋ณดํ†ต ๋žœ๋คํ•œ ๋ฐ์ดํ„ฐ๋ฅผ ๋งŒ๋‚˜๋ฉด ๋‘ ๋ฐฐ ๊ฐ€๊นŒ์ด ๋ถ€ํ’€์–ด ์˜ค๋ฅด๋Š”๋ฐ, ์—ฌ๊ธฐ์„œ๋Š” 3๋ถ„์˜ 1 ๋กœ ์ค„์—ˆ๋‹ค. 0 ์ด ๊ธธ๊ฒŒ ์ด์–ด์ง€๋Š” ๊ตฌ๊ฐ„์ด ์•„์ฃผ ๋งŽ๋‹ค๋Š” ๋œป์ด๊ณ , ํฐ ๋‹จ์ƒ‰ ์˜์—ญ์„ ๊ฐ€์ง„ ๊ทธ๋ฆผ์ด๋ผ๋Š” ํžŒํŠธ๋‹ค.

๋ณธ๋ฌธ ์ฒซ ์„ธ ๋ฐ”์ดํŠธ๋ฅผ LSB-first ๋กœ ํŽด๋ฉด 001001101111000101100100 ์ด๋‹ค. ์†์œผ๋กœ ์„ธ ์ฝ”๋“œ์›Œ๋“œ๋งŒ ์ฝ์–ด ๋ณด์ž.

์ฝ์€ ๋น„ํŠธํ•ด์„๋ฑ‰๋Š” ์›๋ณธ ๋น„ํŠธ
0 0k=0 ์ด๋ผ nbits=1, ๊ฐ’ 0 โ†’ count=01
10 01k=1 ์ด๋ผ nbits=2, LSB-first ๋กœ 0ยท1 โ†’ count=2001
10 11k=1 ์ด๋ผ nbits=2, LSB-first ๋กœ 1ยท1 โ†’ count=30001

์ด์–ด ๋ถ™์ด๋ฉด 1 0 0 1 0 0 0 1 ์ด๊ณ , LSB-first ๋กœ ํ•œ ๋ฐ”์ดํŠธ๋ฅผ ๋งŒ๋“ค๋ฉด 0x89 ๋‹ค. PNG ๋งค์ง ์ฒซ ๋ฐ”์ดํŠธ๊ฐ€ ์†์œผ๋กœ ๊ณ„์‚ฐํ•ด์„œ ๋‚˜์™”๋‹ค. ์ด์ œ ์ฝ”๋“œ๋กœ ์˜ฎ๊ธฐ๋ฉด ๋œ๋‹ค.


๐Ÿ› ์—ฌ๊ธฐ์„œ ํ•œ ๋ฒˆ ํฌ๊ฒŒ ํ—ค๋งธ๋‹ค

โ–ถ๐Ÿ› ์‚ฝ์งˆ โ€” 1 ์„ ์„ธ๋Š” ์ค„ ์•Œ๊ณ  ์ง  ๋””์ฝ”๋”, ๊ฒฐ๊ณผ๊ฐ€ ํ†ต์งธ๋กœ ๋น„ํŠธ ๋ฐ˜์ „๋๋‹ค

์ฒ˜์Œ ๋””์ฝ”๋”๋ฅผ ์งค ๋•Œ test eax,eax ๋‹ค์Œ์˜ je ๋ฅผ ๋Œ€์ถฉ "๋น„ํŠธ๊ฐ€ 1 ์ด๋ฉด ์„ผ๋‹ค" ๋กœ ์ฝ๊ณ  ๋„˜์–ด๊ฐ”๋‹ค. ์–ด์…ˆ๋ธ”๋ฆฌ๋ฅผ ์ฝ๋‹ค ๋ณด๋ฉด ์กฐ๊ฑด์ด ๋’ค์ง‘ํžŒ ์ชฝ์ด ์˜คํžˆ๋ ค ์ž์—ฐ์Šค๋Ÿฌ์›Œ ๋ณด์ผ ๋•Œ๊ฐ€ ์žˆ๋Š”๋ฐ ์—ฌ๊ธฐ๊ฐ€ ๊ทธ๋žฌ๋‹ค.

๊ทธ๋ž˜์„œ ๋งŒ๋“  ๊ฒŒ ์•„๋ž˜ ๋””์ฝ”๋”๋‹ค. ๋Ÿฐ์˜ ๋Œ€์ƒ๋งŒ 1 ๋กœ ๋ฐ”๊ฟจ์„ ๋ฟ ๋‚˜๋จธ์ง€๋Š” ์ตœ์ข…๋ณธ๊ณผ ๊ฐ™๋‹ค.

#!/usr/bin/env python3
"""์‚ฝ์งˆ ๊ธฐ๋ก โ€” encode() ์˜ `test eax,eax; je` ๋ฅผ '1 ์ด๋ฉด ์„ผ๋‹ค'๋กœ ์ž˜๋ชป ์ฝ์—ˆ์„ ๋•Œ์˜ ๋””์ฝ”๋”.
 
๋Ÿฐ์˜ ๋Œ€์ƒ์„ 1 ๋กœ ๋‘๋ฉด ๋ณต์›๋ณธ์ด ์ •๋‹ต์˜ ์ „ ๋น„ํŠธ ๋ฐ˜์ „๋ณธ์ด ๋œ๋‹ค.
๊ฒฐ๊ณผ๊ฐ€ '๋ฐ์ดํ„ฐ'๋กœ๋งŒ ๋ณด์—ฌ์„œ ํ•œ์ฐธ์„ ๋”ด ๋ฐ์„œ ์›์ธ์„ ์ฐพ์•˜๋‹ค.
"""
import sys
 
from decode import BitReader
 
 
def decode_ones(blob):
    n_bits = int.from_bytes(blob[:8], 'little')
    br = BitReader(blob[8:])
    out = bytearray((n_bits + 7) // 8)
    pos = 0
    while pos < n_bits:
        try:
            k = 0
            while br.bit():
                k += 1
            count = 0
            for j in range(k + 1):
                count |= br.bit() << j
        except EOFError:
            break
        for _ in range(count):          # โ† ์—ฌ๊ธฐ๊ฐ€ ํ‹€๋ ธ๋‹ค: 1 ์„ count ๊ฐœ ์ฑ„์šด๋‹ค
            if pos >= n_bits:
                break
            out[pos >> 3] |= 1 << (pos & 7)
            pos += 1
        pos += 1                        # ๋Ÿฐ์„ ๋๋‚ด๋Š” 0 (๊ทธ๋ƒฅ ๊ฑด๋„ˆ๋›ด๋‹ค)
    return bytes(out[:n_bits // 8])
 
 
if __name__ == '__main__':
    res = decode_ones(open(sys.argv[1], 'rb').read())
    print(f'๋ณต์› {len(res)}B, ์•ž 16๋ฐ”์ดํŠธ = {res[:16].hex(" ")}')
    print(f'ASCII                = {res[:16]!r}')
    print(f'PNG ๋งค์ง์ธ๊ฐ€?          {res[:4] == b"\\x89PNG"}')
    print(f'๊ฐ ๋ฐ”์ดํŠธ๋ฅผ ๋ฐ˜์ „ํ•˜๋ฉด    {bytes(b ^ 0xff for b in res[:8])!r}   <- ์ •๋‹ต์ด ์—ฌ๊ธฐ ์žˆ์—ˆ๋‹ค')
python3 decode_wrong.py extracted/flag.enc

decode_wrong.py ์‹คํ–‰ ๊ฒฐ๊ณผ โ€” ๋ณต์›์€ 491123๋ฐ”์ดํŠธ๋กœ ๋๊นŒ์ง€ ๋Œ์•˜์ง€๋งŒ ์•ž 16๋ฐ”์ดํŠธ๊ฐ€ 76 af b1 b8 ๋กœ ์‹œ์ž‘ํ•ด PNG ๋งค์ง์ด ์•„๋‹ˆ๋ฉฐ ๊ฐ ๋ฐ”์ดํŠธ๋ฅผ 0xff ๋กœ ๋ฐ˜์ „ํ•˜๋ฉด ๊ทธ์ œ์•ผ 89 50 4e 47 ์ฆ‰ PNG ๋งค์ง์ด ๋‚˜์˜จ๋‹ค
decode_wrong.py ์‹คํ–‰ ๊ฒฐ๊ณผ โ€” ๋ณต์›์€ 491123๋ฐ”์ดํŠธ๋กœ ๋๊นŒ์ง€ ๋Œ์•˜์ง€๋งŒ ์•ž 16๋ฐ”์ดํŠธ๊ฐ€ 76 af b1 b8 ๋กœ ์‹œ์ž‘ํ•ด PNG ๋งค์ง์ด ์•„๋‹ˆ๋ฉฐ ๊ฐ ๋ฐ”์ดํŠธ๋ฅผ 0xff ๋กœ ๋ฐ˜์ „ํ•˜๋ฉด ๊ทธ์ œ์•ผ 89 50 4e 47 ์ฆ‰ PNG ๋งค์ง์ด ๋‚˜์˜จ๋‹ค

๋ฌธ์ œ๋Š” ์ด๊ฒŒ ๊น”๋”ํ•˜๊ฒŒ ์‹คํŒจํ•˜์ง€ ์•Š๋Š”๋‹ค๋Š” ๊ฒƒ์ด๋‹ค. ๋ณต์› ๋น„ํŠธ ์ˆ˜๋Š” 3,928,984 / 3,928,984 ๋กœ ๋๊นŒ์ง€ ๋”ฑ ๋งž๊ณ , ํฌ๊ธฐ๋„ ํ—ค๋”๊ฐ€ ๋งํ•œ 491,123 ๋ฐ”์ดํŠธ๊ฐ€ ๊ทธ๋Œ€๋กœ ๋‚˜์˜จ๋‹ค. ์ฝ”๋“œ์›Œ๋“œ ๋ฌธ๋ฒ• ์ž์ฒด๋Š” ๋งž๊ฒŒ ์ฝ๊ณ  ์žˆ์œผ๋‹ˆ ์ค‘๊ฐ„์— ์–ด๊ธ‹๋‚  ๋ฐ๊ฐ€ ์—†๋‹ค. ๋‹ค๋งŒ ๋ฑ‰๋Š” ๊ฐ’์ด ์ „๋ถ€ ๋ฐ˜๋Œ€์ผ ๋ฟ์ด๋‹ค.

file ์€ ๊ฒฐ๊ณผ๋ฌผ์„ ๊ทธ๋ƒฅ data ๋ผ๊ณ  ํ–ˆ๊ณ , ๋‚˜๋Š” ํ—ค๋” ํŒŒ์‹ฑ์ด๋‚˜ ๋น„ํŠธ ์ˆœ์„œ๋ฅผ ํ•œ์ฐธ ์˜์‹ฌํ–ˆ๋‹ค. ์•ž 16๋ฐ”์ดํŠธ๊ฐ€ 76 af b1 b8 f2 f5 e5 f5 ff ff ff f2 โ€ฆ ์ธ๋ฐ ff ๊ฐ€ ์ž”๋œฉ ๋ณด์ด๋Š” ๊ฒŒ ์ด์ƒํ•ด์„œ ๋ฐ˜์ „ํ•ด ๋ดค๋”๋‹ˆ 89 50 4e 47, PNG ์˜€๋‹ค.

์ „ ๋น„ํŠธ๊ฐ€ ๋ฐ˜์ „๋๋‹ค๋Š” ๊ฑด 0 ๊ณผ 1 ์˜ ์—ญํ• ๋งŒ ๋ฐ”๋€Œ์—ˆ๋‹ค๋Š” ๋œป์ด๊ณ , ๊ทธ๋Ÿผ ์›์ธ์€ ๋Ÿฐ์˜ ๋Œ€์ƒ ํ•˜๋‚˜๋ฟ์ด๋‹ค. objdump ๋กœ ๋Œ์•„๊ฐ€ cab: je c7f ๋ฅผ ๋‹ค์‹œ ๋ณด๋‹ˆ ์ ํ”„ ๋Œ€์ƒ 0xc7f ๊ฐ€ count++ ํ•˜๋Š” ์ž๋ฆฌ์˜€๋‹ค. je ๋‹ˆ๊นŒ 0 ์ผ ๋•Œ ๋›ด๋‹ค. ์„ธ๋Š” ๊ฑด 0 ์ด์—ˆ๋‹ค.

"๋ณต์›์ด ๋๊นŒ์ง€ ๋Œ์•˜๋‹ค" ๋Š” ๊ฒƒ ์ž์ฒด๋Š” ์•„๋ฌด ๋ณด์ฆ๋„ ์•„๋‹ˆ๋‹ค. ์ด ๋ฌธ์ œ์ฒ˜๋Ÿผ ์ฝ”๋“œ์›Œ๋“œ ๋ฌธ๋ฒ•๊ณผ ๊ฐ’ ํ•ด์„์ด ๋ถ„๋ฆฌ๋ผ ์žˆ์œผ๋ฉด, ๊ฐ’์„ ํ†ต์งธ๋กœ ํ‹€๋ ค๋„ ๊ธธ์ด ๊ณ„์‚ฐ์€ ์™„๋ฒฝํ•˜๊ฒŒ ๋งž์•„๋–จ์–ด์ง„๋‹ค. ํฌ๋งท์„ ๋˜๊ฐ์„ ๋•Œ๋Š” ๊ธธ์ด๊ฐ€ ์•„๋‹ˆ๋ผ ๋งค์ง ๋„˜๋ฒ„ ๊ฐ™์€ ๋…๋ฆฝ ์ง€ํ‘œ๋กœ ํŒ์ •ํ•ด์•ผ ํ•œ๋‹ค.



๐ŸŽฏ ๋””์ฝ”๋”

์—ญํ•จ์ˆ˜๋Š” ์งง๋‹ค. ํ—ค๋”์—์„œ ์›๋ณธ ๋น„ํŠธ ์ˆ˜๋ฅผ ์ฝ๊ณ , ์ฝ”๋“œ์›Œ๋“œ๋ฅผ ํ•˜๋‚˜์”ฉ ํ’€์–ด 0 ์„ count ๊ฐœ, 1 ์„ ํ•˜๋‚˜์”ฉ ์ฑ„์šฐ๋ฉด ๋œ๋‹ค. ์ถœ๋ ฅ ๋ฒ„ํผ๋ฅผ 0 ์œผ๋กœ ์‹œ์ž‘ํ•˜๋ฉด 0 ์€ ๊ทธ๋ƒฅ ๊ฑด๋„ˆ๋›ฐ๊ณ  1 ๋งŒ ์„ธ์›Œ๋„ ๋œ๋‹ค.

#!/usr/bin/env python3
"""main ๋ฐ”์ด๋„ˆ๋ฆฌ(0-๋Ÿฐ๋ ์Šค + Elias-gamma ์ธ์ฝ”๋”)์˜ ์—ญํ•จ์ˆ˜.
 
ํŒŒ์ผ ํฌ๋งท : [8๋ฐ”์ดํŠธ LE = ์›๋ณธ ๋น„ํŠธ์ˆ˜ N] + [์ธ์ฝ”๋”ฉ ๋น„ํŠธ์ŠคํŠธ๋ฆผ, ๋ฐ”์ดํŠธ ์•ˆ์—์„œ LSB-first]
์ฝ”๋“œ์›Œ๋“œ  : (nbits-1)๊ฐœ์˜ 1 โ†’ 0 โ†’ count ์˜ nbits ๋น„ํŠธ(LSB-first)
๋ณต์›      : count ๊ฐœ์˜ 0 ๋น„ํŠธ + 1 ๋น„ํŠธ ํ•˜๋‚˜  ๋ฅผ ์ด์–ด ๋ถ™์—ฌ N ๋น„ํŠธ๋ฅผ ์ฑ„์šด๋‹ค
            (encode 0xc60 ์˜ `test eax,eax; je` ๊ฐ€ '0 ์„ ์„ธ๋Š”' ๋ฃจํ”„๋ผ๋Š” ์ ์ด ํ•ต์‹ฌ)
"""
import sys
 
 
class BitReader:
    def __init__(self, data):
        self.d = data
        self.n = len(data) * 8
        self.p = 0
 
    def bit(self):
        i = self.p
        if i >= self.n:
            raise EOFError
        self.p = i + 1
        return (self.d[i >> 3] >> (i & 7)) & 1
 
 
def decode(blob):
    n_bits = int.from_bytes(blob[:8], 'little')      # src->cap = ์›๋ณธ ๋ฐ”์ดํŠธ์ˆ˜ * 8
    br = BitReader(blob[8:])
    out = bytearray((n_bits + 7) // 8)               # 0 ์œผ๋กœ ์‹œ์ž‘ โ†’ 0 ๋น„ํŠธ๋Š” ๊ทธ๋ƒฅ ๊ฑด๋„ˆ๋›ด๋‹ค
    pos = 0
    while pos < n_bits:
        try:
            k = 0                                    # 0 ์ด ๋‚˜์˜ฌ ๋•Œ๊นŒ์ง€ 1 ์„ ์„ผ๋‹ค โ†’ nbits = k+1
            while br.bit():
                k += 1
            count = 0
            for j in range(k + 1):                   # count ์˜ ๋น„ํŠธ๋ฅผ LSB-first ๋กœ
                count |= br.bit() << j
        except EOFError:
            break
        pos += count                                 # 0 ์ด count ๊ฐœ
        if pos < n_bits:                             # ๋Ÿฐ์„ ๋๋‚ด๋Š” 1
            out[pos >> 3] |= 1 << (pos & 7)
            pos += 1
    return bytes(out[:n_bits // 8]), pos, n_bits
 
 
if __name__ == '__main__':
    src, dst = sys.argv[1], sys.argv[2]
    blob = open(src, 'rb').read()
    res, pos, n_bits = decode(blob)
    open(dst, 'wb').write(res)
    print(f'{src} ({len(blob)}B) -> {dst} ({len(res)}B), ๋ณต์› ๋น„ํŠธ {pos}/{n_bits}')

์›๋ณธ ๋น„ํŠธ ์ˆ˜ n_bits ๋กœ ๋Š๋Š” ๊ฒŒ ์ค‘์š”ํ•˜๋‹ค. flush ๊ฐ€ ๊ผฌ๋ฆฌ๋ฅผ 1 ๋กœ ์ฑ„์›Œ ๋†จ๊ธฐ ๋•Œ๋ฌธ์—, ๋๊นŒ์ง€ ์ฝ์œผ๋ฉด ์žˆ์ง€๋„ ์•Š์€ ์ฝ”๋“œ์›Œ๋“œ๋ฅผ ๋ช‡ ๊ฐœ ๋” ๋งŒ๋“ค์–ด ๋‚ธ๋‹ค. ๊ธธ์ด๋ฅผ ์•Œ๊ณ  ์žˆ์œผ๋‹ˆ ๊ฑฐ๊ธฐ์„œ ๋ฉˆ์ถ”๋ฉด ๊ทธ๋งŒ์ด๋‹ค.


๐Ÿš€ Full Exploit

๋ณต์›ํ•œ PNG ๋Š” 10000ร—10000 ์งœ๋ฆฌ๋ผ ๊ทธ๋ฆผ ์ „์ฒด๋ฅผ ๋ˆˆ์œผ๋กœ ํ›‘๊ธฐ๊ฐ€ ๋ฒˆ๊ฑฐ๋กญ๋‹ค. ๋ฐฐ๊ฒฝ์ด ์™„์ „ํ•œ ๊ฒ€์ •์ด๊ณ  ๊ธ€์ž๋งŒ ํฐ์ƒ‰์ด๋ผ, ์ž‰ํฌ๊ฐ€ ์žˆ๋Š” ์˜์—ญ์˜ ๊ฒฝ๊ณ„ ์ƒ์ž๋ฅผ ๊ตฌํ•˜๋ฉด ๊ธ€์ž ์ค„์ด ๋ฐ”๋กœ ์žกํžŒ๋‹ค. ๋‹ค๋งŒ ์˜ค๋ฅธ์ชฝ์— ๋Ÿฌ๋„ˆ ์•„์ด์ฝ˜์ด ํ•˜๋‚˜ ๋” ์žˆ์–ด์„œ ๊ฒฝ๊ณ„ ์ƒ์ž๋ฅผ ๊ทธ๋Œ€๋กœ ์“ฐ๋ฉด ์„ธ๋กœ๋กœ ๋„ˆ๋ฌด ๊ธธ์–ด์ง„๋‹ค. ์—ด ๋‹จ์œ„๋กœ ์ž‰ํฌ ํ•ฉ์„ ๋‚ด์„œ ๊ฐ€์žฅ ๋„“์€ ๋นˆ ๊ตฌ๊ฐ„์„ ์ฐพ๊ณ  ๊ทธ ์™ผ์ชฝ๋งŒ ๋‚จ๊ธฐ๋ฉด ๊ธ€์ž ์ค„๋งŒ ๋–จ์–ด์ง„๋‹ค.

๊ฑฐ๊ธฐ๊นŒ์ง€ ์ž๋ฅด๋ฉด tesseract ๊ฐ€ ๋ฐ”๋กœ ์ฝ๋Š”๋‹ค. ํ•œ ๊ฐ€์ง€ ์ฃผ์˜ํ•  ์ ์€ ์„ธ๊ทธ๋จผํ…Œ์ด์…˜ ๋ชจ๋“œ๋‹ค. ๊ธฐ๋ณธ๊ฐ’์ด๋‚˜ --psm 7 ๋กœ ์ฝ์œผ๋ฉด ๋ฐ‘์ค„์„ ๊ณต๋ฐฑ์œผ๋กœ ๋ฑ‰์–ด์„œ GoN{run length encoding} ์ด ๋˜๋Š”๋ฐ, --psm 13(raw line) ์œผ๋กœ ์ฝ์œผ๋ฉด ๋ฐ‘์ค„์ด ์‚ด์•„๋‚œ๋‹ค.

#!/usr/bin/env python3
"""Run (DreamHack Platinum 4) โ€” flag.enc ํ•œ ๋ฐฉ ๋ณต์›.
 
1) flag.enc ๋ฅผ ์—ญRLE-gamma ๋กœ ํ’€์–ด ์›๋ณธ PNG ๋ฅผ ๋˜์‚ด๋ฆฐ๋‹ค  (decode.py)
2) ๋˜์‚ด๋ฆฐ 10000x10000 PNG ์—์„œ ์ž‰ํฌ๊ฐ€ ์žˆ๋Š” ์˜์—ญ์„ ์ฐพ๊ณ , ์˜ค๋ฅธ์ชฝ ๋Ÿฌ๋„ˆ ์•„์ด์ฝ˜์„
   ๊ฐ€์žฅ ๋„“์€ ๋นˆ ์—ด ๊ตฌ๊ฐ„์—์„œ ์ž˜๋ผ๋‚ด ๊ธ€์ž ์ค„๋งŒ ๋‚จ๊ธด๋‹ค
3) ๊ทธ ์กฐ๊ฐ์„ tesseract ๋กœ ์ฝ์–ด flag ๋ฌธ์ž์—ด์„ ๋ฝ‘๋Š”๋‹ค
"""
import re
import subprocess
import sys
 
from PIL import Image, ImageOps
 
from decode import decode
 
Image.MAX_IMAGE_PIXELS = None          # ์šฐ๋ฆฌ๊ฐ€ ๋ฐฉ๊ธˆ ๋งŒ๋“  ํŒŒ์ผ์ด๋ผ ํญํƒ„ ๊ฒฝ๊ณ ๋Š” ๋ฌด์˜๋ฏธํ•˜๋‹ค
 
SRC = sys.argv[1] if len(sys.argv) > 1 else 'extracted/flag.enc'
PNG = sys.argv[2] if len(sys.argv) > 2 else 'flag.png'
CROP = 'flag_crop.png'
 
 
def split_off_icon(ink):
    """์—ด ๋‹จ์œ„ ์ž‰ํฌ ํ•ฉ์—์„œ ๊ฐ€์žฅ ๊ธด ๋นˆ ๊ตฌ๊ฐ„์„ ์ฐพ์•„ ๊ทธ ์™ผ์ชฝ(=๊ธ€์ž ์ค„)๋งŒ ๋Œ๋ ค์ค€๋‹ค."""
    w, h = ink.size
    col = [0] * w
    px = ink.load()
    for x in range(w):
        s = 0
        for y in range(0, h, 4):       # 4ํ–‰๋งˆ๋‹ค ํ›‘์–ด๋„ ๋นˆ ์—ด ํŒ์ •์—๋Š” ์ถฉ๋ถ„ํ•˜๋‹ค
            s += px[x, y]
        col[x] = s
    best_len, best_end, run = 0, 0, 0
    for x in range(w):
        if col[x] == 0:
            run += 1
            if run > best_len:
                best_len, best_end = run, x
        else:
            run = 0
    if best_len < 40:                  # ๋šœ๋ ทํ•œ ๊ณต๋ฐฑ์ด ์—†์œผ๋ฉด ํ†ต์งธ๋กœ ์“ด๋‹ค
        return ink.getbbox()
    cut = best_end - best_len + 1
    return ink.crop((0, 0, cut, h)).getbbox()
 
 
def main():
    blob = open(SRC, 'rb').read()
    png, pos, n_bits = decode(blob)
    open(PNG, 'wb').write(png)
    print(f'[1] {SRC} ({len(blob)}B) -> {PNG} ({len(png)}B), ๋ณต์› ๋น„ํŠธ {pos}/{n_bits}')
    print(f'[1] magic = {png[:8].hex(" ")}')
 
    im = Image.open(PNG)
    print(f'[2] ๋ณต์›๋œ ์ด๋ฏธ์ง€: {im.size[0]}x{im.size[1]} {im.mode}')
 
    gray = im.convert('L')                       # ์•ŒํŒŒ๋ฅผ ๋ฒ„๋ฆฌ๊ณ  ๋ฐ๊ธฐ๋งŒ ๋ณธ๋‹ค
    ink = gray.point(lambda p: 255 if p > 40 else 0)
    box = ink.getbbox()
    print(f'[2] ์ž‰ํฌ ์ „์ฒด ์˜์—ญ = {box}')
 
    sub = ink.crop(box)
    tb = split_off_icon(sub)
    text_box = (box[0] + tb[0], box[1] + tb[1], box[0] + tb[2], box[1] + tb[3])
    print(f'[2] ์•„์ด์ฝ˜์„ ๋—€ ๊ธ€์ž ์˜์—ญ = {text_box}')
 
    crop = gray.crop(text_box)
    ImageOps.expand(ImageOps.invert(crop), border=60, fill=255).save(CROP)
    print(f'[2] {CROP} ์ €์žฅ ({crop.size[0]}x{crop.size[1]})')
 
    raw = subprocess.run(['tesseract', CROP, '-', '--psm', '13'],
                         capture_output=True, text=True).stdout.strip()
    print(f'[3] tesseract ์›๋ฌธ = {raw!r}')
    m = re.search(r'GoN\{[^}]*\}', raw)
    print(f'[3] FLAG = {m.group(0) if m else "(๋ชป ์ฐพ์Œ)"}')
    return 0 if m else 1
 
 
if __name__ == '__main__':
    sys.exit(main())
python3 solve.py

solve.py ์‹คํ–‰ ๊ฒฐ๊ณผ โ€” flag.enc 160672๋ฐ”์ดํŠธ๋ฅผ flag.png 491123๋ฐ”์ดํŠธ๋กœ ๋ณต์›ํ•˜๊ณ  ๋งค์ง์ด 89 50 4e 47 ๋กœ ์ฐํžˆ๋ฉฐ 10000x10000 ์ด๋ฏธ์ง€์—์„œ ๊ธ€์ž ์ค„๋งŒ ์ž˜๋ผ tesseract ๋กœ ํ”Œ๋ž˜๊ทธ๋ฅผ ์ฝ์–ด ๋‚ธ๋‹ค
solve.py ์‹คํ–‰ ๊ฒฐ๊ณผ โ€” flag.enc 160672๋ฐ”์ดํŠธ๋ฅผ flag.png 491123๋ฐ”์ดํŠธ๋กœ ๋ณต์›ํ•˜๊ณ  ๋งค์ง์ด 89 50 4e 47 ๋กœ ์ฐํžˆ๋ฉฐ 10000x10000 ์ด๋ฏธ์ง€์—์„œ ๊ธ€์ž ์ค„๋งŒ ์ž˜๋ผ tesseract ๋กœ ํ”Œ๋ž˜๊ทธ๋ฅผ ์ฝ์–ด ๋‚ธ๋‹ค

๋ณต์›ํ•œ ๊ทธ๋ฆผ์ด ์‹ค์ œ๋กœ ์–ด๋–ป๊ฒŒ ์ƒ๊ฒผ๋Š”์ง€๋„ ๋ณด์ž. 10000ร—10000 ์„ 1000ร—1000 ์œผ๋กœ ์ค„์ด๊ณ , ๊ธ€์ž ์ค„๋งŒ ์›๋ณธ ํ•ด์ƒ๋„๋กœ ํ•œ ๋ฒˆ ๋” ์ž˜๋ผ ๋‚ธ๋‹ค.

#!/usr/bin/env python3
"""๋ณต์›ํ•œ flag.png ๋กœ ๊ธ€์— ๋„ฃ์„ ๊ทธ๋ฆผ ๋‘ ์žฅ์„ ๋งŒ๋“ ๋‹ค.
 
  12_preview.png : 10000x10000 ์›๋ณธ์„ 1000x1000 ์œผ๋กœ ์ค„์ธ ์ „์ฒด ๋ฏธ๋ฆฌ๋ณด๊ธฐ
  13_flag.png    : ๊ธ€์ž ์ค„๋งŒ ์ž˜๋ผ๋‚ธ ์›๋ณธ ์ƒ‰(๊ฒ€์ • ๋ฐฐ๊ฒฝ ํฐ ๊ธ€์ž) ์กฐ๊ฐ
"""
from PIL import Image
 
Image.MAX_IMAGE_PIXELS = None
OUT = '/home/jinho/homepage/public/images/blog/dreamhack-run-writeup'
 
im = Image.open('flag.png').convert('RGB')
im.resize((1000, 1000), Image.LANCZOS).save(f'{OUT}/12_preview.png')
print(f'12_preview.png  <- {im.size[0]}x{im.size[1]} ๋ฅผ 1000x1000 ์œผ๋กœ')
 
box = (3900, 9140, 8120, 9540)          # solve.py ๊ฐ€ ์ฐ์–ด ์ค€ ๊ธ€์ž ์˜์—ญ์— ์—ฌ๋ฐฑ์„ ๋”ํ•œ ๊ฐ’
im.crop(box).save(f'{OUT}/13_flag.png')
print(f'13_flag.png     <- crop{box} = {box[2] - box[0]}x{box[3] - box[1]}')
python3 make_figs.py

๋ณต์›ํ•œ 10000x10000 PNG ๋ฅผ 1000x1000 ์œผ๋กœ ์ค„์ธ ์ „์ฒด ๋ฏธ๋ฆฌ๋ณด๊ธฐ โ€” ํ™”๋ฉด ๋Œ€๋ถ€๋ถ„์ด ๊ฒ€์ •์ด๊ณ  ์˜ค๋ฅธ์ชฝ ์•„๋ž˜ ๊ตฌ์„์—๋งŒ ํ”Œ๋ž˜๊ทธ ๋ฌธ์ž์—ด๊ณผ ๋‹ฌ๋ฆฌ๋Š” ์‚ฌ๋žŒ ํ”ฝํ† ๊ทธ๋žจ์ด ์ž‘๊ฒŒ ๋†“์—ฌ ์žˆ๋‹ค
๋ณต์›ํ•œ 10000x10000 PNG ๋ฅผ 1000x1000 ์œผ๋กœ ์ค„์ธ ์ „์ฒด ๋ฏธ๋ฆฌ๋ณด๊ธฐ โ€” ํ™”๋ฉด ๋Œ€๋ถ€๋ถ„์ด ๊ฒ€์ •์ด๊ณ  ์˜ค๋ฅธ์ชฝ ์•„๋ž˜ ๊ตฌ์„์—๋งŒ ํ”Œ๋ž˜๊ทธ ๋ฌธ์ž์—ด๊ณผ ๋‹ฌ๋ฆฌ๋Š” ์‚ฌ๋žŒ ํ”ฝํ† ๊ทธ๋žจ์ด ์ž‘๊ฒŒ ๋†“์—ฌ ์žˆ๋‹ค

๊ฑฐ์˜ ์ „๋ถ€๊ฐ€ ๊ฒ€์ •์ด๋‹ค. ์ธ์ฝ”๋”ฉ ๊ฒฐ๊ณผ๊ฐ€ 3๋ถ„์˜ 1 ๋กœ ์ค„์–ด๋“  ์ด์œ ๊ฐ€ ์ด๊ฑฐ๋‹ค. ๊ฒ€์€ ํ”ฝ์…€์ด ์ด์–ด์ง€๋Š” ๊ตฌ๊ฐ„์—์„œ 0 ๋Ÿฐ์ด ์•„์ฃผ ๊ธธ์–ด์ง€๊ณ , ๋Ÿฐ ํ•˜๋‚˜๊ฐ€ ์•„๋ฌด๋ฆฌ ๊ธธ์–ด๋„ ์ฝ”๋“œ์›Œ๋“œ๋Š” ๋ช‡ ์‹ญ ๋น„ํŠธ๋ฅผ ๋„˜์ง€ ์•Š๋Š”๋‹ค.

์˜ค๋ฅธ์ชฝ ์•„๋ž˜๋ฅผ ์›๋ณธ ํ•ด์ƒ๋„๋กœ ์ž๋ฅด๋ฉด ํ”Œ๋ž˜๊ทธ๊ฐ€ ๋‚˜์˜จ๋‹ค.

๋ณต์›ํ•œ ์ด๋ฏธ์ง€์—์„œ ์ž˜๋ผ๋‚ธ ํ”Œ๋ž˜๊ทธ ๋ฌธ์ž์—ด โ€” ๊ฒ€์€ ๋ฐฐ๊ฒฝ์— ํฐ ์‚ฐ์„ธ๋ฆฌํ”„์ฒด๋กœ GoN ์ค‘๊ด„ํ˜ธ run_length_encoding ์ด ๋˜๋ ทํ•˜๊ฒŒ ๋ Œ๋”๋ผ ์žˆ๋‹ค
๋ณต์›ํ•œ ์ด๋ฏธ์ง€์—์„œ ์ž˜๋ผ๋‚ธ ํ”Œ๋ž˜๊ทธ ๋ฌธ์ž์—ด โ€” ๊ฒ€์€ ๋ฐฐ๊ฒฝ์— ํฐ ์‚ฐ์„ธ๋ฆฌํ”„์ฒด๋กœ GoN ์ค‘๊ด„ํ˜ธ run_length_encoding ์ด ๋˜๋ ทํ•˜๊ฒŒ ๋ Œ๋”๋ผ ์žˆ๋‹ค

GoN{run_length_encoding} ์ด๋‹ค. ๋ฌธ์ œ ์ด๋ฆ„ ๊ทธ๋Œ€๋กœ๋‹ค.

ํ”Œ๋ž˜๊ทธ๊ฐ€ ๋ฌธ์ž์—ด์ด ์•„๋‹ˆ๋ผ ๊ทธ๋ฆผ์œผ๋กœ ๋ Œ๋”๋ผ ์žˆ์œผ๋‹ˆ, ๋ฐ”์ด๋„ˆ๋ฆฌ๋“  ๋ณต์›๋ณธ์ด๋“  strings ๋‚˜ grep ์œผ๋กœ๋Š” ์˜์›ํžˆ ์•ˆ ์žกํžŒ๋‹ค. flag.enc ๋ฅผ ์•„๋ฌด๋ฆฌ ๋’ค์ ธ๋„ GoN ์ด ์•ˆ ๋‚˜์˜ค๋Š” ๊ฒŒ ์ •์ƒ์ด๋‹ค.



โœ… ๊ฒ€์ฆ โ€” ๋ณต์›๋ณธ์„ ๋ฌธ์ œ ๋ฐ”์ด๋„ˆ๋ฆฌ์— ๋‹ค์‹œ ๋จน์ธ๋‹ค

๋ณต์›์ด ๋งž๋Š”์ง€ ํŒ์ •ํ•˜๋Š” ๊ฐ€์žฅ ํ™•์‹คํ•œ ๋ฐฉ๋ฒ•์€ ๋ฌธ์ œ ๋ฐ”์ด๋„ˆ๋ฆฌ๋ฅผ ์˜ค๋ผํด๋กœ ์“ฐ๋Š” ๊ฒƒ์ด๋‹ค. ๋‚ด๊ฐ€ ๋˜์‚ด๋ฆฐ flag.png ๋ฅผ ๊ทธ๋Œ€๋กœ main ์— ํ†ต๊ณผ์‹œํ‚ค๋ฉด, ๋ชจ๋ธ์ด ์ •ํ™•ํ•  ๋•Œ๋งŒ ๋ฐฐํฌ๋œ flag.enc ์™€ ๋ฐ”์ดํŠธ ๋‹จ์œ„๋กœ ๊ฐ™์€ ํŒŒ์ผ์ด ๋‚˜์˜จ๋‹ค.

#!/usr/bin/env bash
# ๋ณต์›ํ•œ flag.png ๋ฅผ ๋ฌธ์ œ ๋ฐ”์ด๋„ˆ๋ฆฌ์— ๊ทธ๋Œ€๋กœ ์žฌํˆฌ์ž…ํ•ด ๋ฐฐํฌ๋ณธ flag.enc ์™€ ๋Œ€์กฐํ•œ๋‹ค.
set -eu
cd "$(dirname "$(readlink -f "$0")")"
mkdir -p roundtrip && cp flag.png roundtrip/flag.png
( cd roundtrip && ../extracted/main flag.png )
sha256sum roundtrip/flag.png.enc extracted/flag.enc
if cmp -s roundtrip/flag.png.enc extracted/flag.enc; then
  echo "MATCH: ์žฌ์ธ์ฝ”๋”ฉ ๊ฒฐ๊ณผ๊ฐ€ ๋ฐฐํฌ๋ณธ๊ณผ ๋ฐ”์ดํŠธ ๋‹จ์œ„๋กœ ๊ฐ™๋‹ค"
else
  echo "DIFF: ๋ชจ๋ธ์ด ํ‹€๋ ธ๋‹ค"; exit 1
fi
./roundtrip.sh

roundtrip.sh ์‹คํ–‰ ๊ฒฐ๊ณผ โ€” ๋ณต์›ํ•œ flag.png ๋ฅผ ๋ฌธ์ œ ๋ฐ”์ด๋„ˆ๋ฆฌ์— ๋‹ค์‹œ ๋„ฃ์–ด ๋งŒ๋“  flag.png.enc ์˜ sha256 ์ด 23cc8006 ์œผ๋กœ ์‹œ์ž‘ํ•˜๋Š” ๊ฐ’์œผ๋กœ ๋ฐฐํฌ๋ณธ flag.enc ์™€ ์™„์ „ํžˆ ์ผ์น˜ํ•œ๋‹ค
roundtrip.sh ์‹คํ–‰ ๊ฒฐ๊ณผ โ€” ๋ณต์›ํ•œ flag.png ๋ฅผ ๋ฌธ์ œ ๋ฐ”์ด๋„ˆ๋ฆฌ์— ๋‹ค์‹œ ๋„ฃ์–ด ๋งŒ๋“  flag.png.enc ์˜ sha256 ์ด 23cc8006 ์œผ๋กœ ์‹œ์ž‘ํ•˜๋Š” ๊ฐ’์œผ๋กœ ๋ฐฐํฌ๋ณธ flag.enc ์™€ ์™„์ „ํžˆ ์ผ์น˜ํ•œ๋‹ค

sha256 ์ด ๊ฐ™๋‹ค. ๋น„ํŠธ ์ˆœ์„œ, ์ฝ”๋“œ์›Œ๋“œ ๋ฌธ๋ฒ•, ๋Ÿฐ์˜ ๋Œ€์ƒ, ๊ผฌ๋ฆฌ ํŒจ๋”ฉ, ํ—ค๋”๊นŒ์ง€ ์ „๋ถ€ ๋งž์•˜๋‹ค๋Š” ๋œป์ด๊ณ , ๋ˆˆ์œผ๋กœ ๊ทธ๋ฆผ์„ ๋ณด๊ณ  "๋งž๋Š” ๊ฒƒ ๊ฐ™๋‹ค" ๊ณ  ํŒ๋‹จํ•˜๋Š” ๊ฒƒ๋ณด๋‹ค ํ›จ์”ฌ ๊ฐ•ํ•œ ์ฆ๊ฑฐ๋‹ค.

๋ณต์›๋ณธ์ด ์กฐ๊ธˆ์ด๋ผ๋„ ๋‹ค๋ฅด๋ฉด ๋Ÿฐ ๊ตฌ์กฐ๊ฐ€ ํ†ต์งธ๋กœ ์–ด๊ธ‹๋‚˜ ๊ฒฐ๊ณผ ํŒŒ์ผ ํฌ๊ธฐ๋ถ€ํ„ฐ ๋‹ฌ๋ผ์ง„๋‹ค. ๊ทธ๋ฆผ์ด ๊ทธ๋Ÿด๋“ฏํ•ด ๋ณด์ด๋Š” ๊ฒƒ๊ณผ ์›๋ณธ๊ณผ ๊ฐ™์€ ๊ฒƒ์€ ๋‹ค๋ฅธ ์ด์•ผ๊ธฐ๋ผ, ๋˜๊ฐ๊ธฐ ๋ฌธ์ œ์—์„œ๋Š” ์ด๋Ÿฐ ์™•๋ณต ๊ฒ€์‚ฌ๋ฅผ ํ•œ ๋ฒˆ ๋Œ๋ ค ๋‘๋Š” ๊ฒŒ ํŽธํ•˜๋‹ค.



๐Ÿ“ ๊ฒฐ๋ก 

์„ธ๋Š” ๋Œ€์ƒ์„ ๋ฐ˜๋Œ€๋กœ ์ฝ์–ด๋„ ํ”„๋กœ๊ทธ๋žจ์€ ์•„๋ฌด ๋ถˆํ‰์„ ํ•˜์ง€ ์•Š๋Š”๋‹ค.

je ํ•˜๋‚˜๊ฐ€ jne ์˜€๋‹ค๋ฉด ์ด ๊ธ€์˜ ์ ˆ๋ฐ˜์ด ํ•„์š” ์—†์—ˆ๋‹ค. ๊ทธ๋Ÿฐ๋ฐ ๊ทธ ์‹ค์ˆ˜๋Š” ์˜ˆ์™ธ๋„, ๊ธธ์ด ๋ถˆ์ผ์น˜๋„, ํŒŒ์‹ฑ ์˜ค๋ฅ˜๋„ ๋‚ด์ง€ ์•Š๋Š”๋‹ค. ์ •ํ™•ํžˆ ๊ฐ™์€ ๊ฐœ์ˆ˜์˜ ๋น„ํŠธ๋ฅผ ์ •ํ™•ํžˆ ๋ฐ˜๋Œ€ ๊ฐ’์œผ๋กœ ๋ฑ‰์„ ๋ฟ์ด๋‹ค. ์กฐ๊ฑด ๋ถ„๊ธฐ์˜ ๋ฐฉํ–ฅ์€ "๋Œ€์ถฉ ์ด์ชฝ์ด๊ฒ ์ง€" ๋กœ ๋„˜๊ธฐ๋ฉด ์•ˆ ๋˜๊ณ , ์ ํ”„ ๋Œ€์ƒ ์ฃผ์†Œ๊ฐ€ ์‹ค์ œ๋กœ ๋ฌด์—‡์„ ํ•˜๋Š” ์ž๋ฆฌ์ธ์ง€ ํ•œ ๋ฒˆ ๋” ํ™•์ธํ•ด์•ผ ํ•œ๋‹ค.

ํฌ๋งท์„ ํŒ์ •ํ•  ๋•Œ๋Š” ๊ธธ์ด๊ฐ€ ์•„๋‹ˆ๋ผ ๋‚ด์šฉ์œผ๋กœ ํŒ์ •ํ•œ๋‹ค.

๋ณต์› ๋น„ํŠธ ์ˆ˜๊ฐ€ ํ—ค๋”์™€ ๋”ฑ ๋งž์•˜๊ธฐ ๋•Œ๋ฌธ์— ๋‚˜๋Š” ํ•œ๋™์•ˆ ๋””์ฝ”๋”๋ฅผ ์˜์‹ฌํ•˜์ง€ ์•Š์•˜๋‹ค. ๋งค์ง ๋„˜๋ฒ„, ์ฒดํฌ์„ฌ, ํŒŒ์ผ ๋์˜ ์ข…๊ฒฐ ๊ตฌ์กฐ์ฒ˜๋Ÿผ ๊ฐ’ ์ž์ฒด๊ฐ€ ๊ฑธ๋ฆฌ๋Š” ์ง€ํ‘œ๋ฅผ ํ•˜๋‚˜ ์žก์•„ ๋‘๋ฉด ์ด๋Ÿฐ ์ฐฉ๊ฐ์ด ์˜ค๋ž˜๊ฐ€์ง€ ์•Š๋Š”๋‹ค. ์ด ๋ฌธ์ œ์—์„œ๋Š” 89 50 4e 47 ์ด ๊ทธ ์—ญํ• ์„ ํ–ˆ๋‹ค.

์ง์ ‘ ๋งŒ๋“  ์ธ์ฝ”๋”ฉ์€ ๋น„๋ฐ€์ด ์•„๋‹ˆ๋‹ค.

์ด ๋ฌธ์ œ์˜ flag.enc ๋Š” ์•”ํ˜ธ๊ฐ€ ์•„๋‹ˆ๋ผ ์ž์ฒด ์ œ์ž‘ ์••์ถ•์ด๋‹ค. ํ‚ค๋„ ์—†๊ณ  ๋‚œ์ˆ˜๋„ ์—†์–ด์„œ ์ธ์ฝ”๋” 1810๋ฐ”์ดํŠธ๋งŒ ์ฝ์œผ๋ฉด ์™„์ „ํžˆ ๋ณต์›๋œ๋‹ค. ์‹ค๋ฌด์—์„œ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ์ถœ ๋ชฉ์ ์œผ๋กœ ์‚ฌ๋‚ด ํฌ๋งท์„ ์“ฐ๋Š” ๊ฒฝ์šฐ๊ฐ€ ์žˆ๋Š”๋ฐ, ์ธ์ฝ”๋” ๋ฐ”์ด๋„ˆ๋ฆฌ๊ฐ€ ํ•จ๊ป˜ ๋ฐฐํฌ๋˜๋Š” ์ˆœ๊ฐ„ ๊ทธ๊ฑด ๊ทธ๋ƒฅ ์—ด๋ ค ์žˆ๋Š” ๊ฒƒ์ด๋‹ค. ๊ฐ์ถฐ์•ผ ํ•  ๊ฐ’์€ ํฌ๋งท์ด ์•„๋‹ˆ๋ผ ํ‚ค๋กœ ๊ฐ์‹ธ์•ผ ํ•œ๋‹ค.

ํ”Œ๋ž˜๊ทธ๋ฅผ ๋ฌธ์ž์—ด์ด ์•„๋‹ˆ๋ผ ๊ทธ๋ฆผ์œผ๋กœ ๋‘๋Š” ์ถœ์ œ ๋ฐฉ์‹.

strings ยท grep ยท ์ •์  ๋ฌธ์ž์—ด ์Šค์บ” ๊ฐ™์€ ์ง€๋ฆ„๊ธธ์„ ์ „๋ถ€ ๋ง‰๋Š”๋‹ค. ๋ณต์›๋œ ๋ฐ์ดํ„ฐ๊ฐ€ ํ…์ŠคํŠธ๊ฐ€ ์•„๋‹ˆ๋ฉด ๋ Œ๋”ํ•ด์„œ ๋ˆˆ์œผ๋กœ ๋ด์•ผ ํ•˜๊ณ , ๊ทธ๋Ÿฌ๋ ค๋ฉด ํฌ๋งท์„ ๋๊นŒ์ง€ ์ •ํ™•ํžˆ ๋˜์‚ด๋ ค์•ผ ํ•œ๋‹ค. ์ด ๋ฌธ์ œ๊ฐ€ Platinum ์ธ ์ด์œ ๋Š” ๊ธฐ๋ฒ•์ด ์–ด๋ ค์›Œ์„œ๊ฐ€ ์•„๋‹ˆ๋ผ, ์ค‘๊ฐ„์— ๋Œ€์ถฉ ๋งž์ถ˜ ์ƒํƒœ๋กœ๋Š” ์•„๋ฌด๊ฒƒ๋„ ๋ชป ๋ณด๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

์ด ๊ธ€์ด ๋„์›€์ด ๋๋‚˜์š”?

Comments

๋Œ“๊ธ€

0๊ฐœ

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

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

Related

๊ด€๋ จ ๊ธ€

3๊ฐœ
[๐Ÿ’  Platinum 4] ํ•œ ํ”„๋กœ์„ธ์Šค์—์„œ 32๋น„ํŠธ์™€ 64๋น„ํŠธ๊ฐ€ ๋ฒˆ๊ฐˆ์•„ ๋ˆ๋‹ค โ€” DreamHack conquergent ํ’€์ด
blog

[๐Ÿ’  Platinum 4] ํ•œ ํ”„๋กœ์„ธ์Šค์—์„œ 32๋น„ํŠธ์™€ 64๋น„ํŠธ๊ฐ€ ๋ฒˆ๊ฐˆ์•„ ๋ˆ๋‹ค โ€” DreamHack conquergent ํ’€์ด

๋ฐฐํฌ ํŒŒ์ผ์€ 17KB์งœ๋ฆฌ stripped ELF ํ•˜๋‚˜. 32๋น„ํŠธ i386 ๋ฐ”์ด๋„ˆ๋ฆฌ์ธ๋ฐ .text ์•ˆ์— retf ๊ฐ€ 32๊ฐœ ๋ฐ•ํ˜€ ์žˆ๋‹ค. CS ์…€๋ ‰ํ„ฐ๋ฅผ 0x33 ์œผ๋กœ ๋ฐ€์–ด ๋„ฃ๊ณ  far return ํ•˜๋Š” Heaven's Gate ๋กœ, ๊ฐ™์€ ํ”„๋กœ์„ธ์Šค ์•ˆ์—์„œ 64๋น„ํŠธ ๊ฐ€์ ฏ 14์ข…์„ ๊ตด๋ ค ์ž…๋ ฅ 64๋ฐ”์ดํŠธ๋ฅผ qword 8๊ฐœ ๋‹จ์œ„๋กœ ๋ณ€ํ™˜ํ•œ๋‹ค. objdump ๊ฐ€ dec eax ๋กœ ๋ณด์—ฌ ์ฃผ๋Š” 0x48 ์€ REX.W ์ ‘๋‘์‚ฌ์˜€๋‹ค. ๊ฐ€์ ฏ ๊ทœ์•ฝ๊ณผ ์ƒ์ˆ˜ ํ…Œ์ด๋ธ”์„ ๋„๊ตฌ๋กœ ๋ฝ‘์•„ ์„ธ ๋‹จ๊ณ„ ํŒŒ์ดํ”„๋ผ์ธ์„ ๋ณต์›ํ•˜๊ณ , ๊ณฑ์…ˆ ์ƒ์ˆ˜๊ฐ€ ์ „๋ถ€ ํ™€์ˆ˜๋ผ๋Š” ์ ์„ ์ด์šฉํ•ด mod 2^64 ์—ญ์›์œผ๋กœ ๋˜๊ฐ์•„ ํ”Œ๋ž˜๊ทธ๋ฅผ ๋ณต์›ํ–ˆ๋‹ค.
#dreamhack#ctf#reversing+6
2026-08-18#dreamhack +5
[๐Ÿฅ‡ Gold 4] ํŒŒ์ผ ์ปค์„œ๋ฅผ 656๋ฒˆ ํฉ๋ฟŒ๋ฆฐ ๊ฒ€์ฆ๊ธฐ ๋˜๊ฐ๊ธฐ โ€” DreamHack fverify ํ’€์ด
blog

[๐Ÿฅ‡ Gold 4] ํŒŒ์ผ ์ปค์„œ๋ฅผ 656๋ฒˆ ํฉ๋ฟŒ๋ฆฐ ๊ฒ€์ฆ๊ธฐ ๋˜๊ฐ๊ธฐ โ€” DreamHack fverify ํ’€์ด

fverify ๋Š” fseek(SEEK_CUR) 4949๋ฒˆ๊ณผ 1๋ฐ”์ดํŠธ fread 656๋ฒˆ์œผ๋กœ๋งŒ ์ด๋ฃจ์–ด์ง„ ์ง์„  ์ฝ”๋“œ๋‹ค. ํŒŒ์ผ ์˜คํ”„์…‹์ด ์ฝ”๋“œ ์–ด๋””์—๋„ ์•ˆ ์ ํ˜€ ์žˆ์–ด objdump ์ถœ๋ ฅ๋งŒ์œผ๋กœ๋Š” ๋ฌด์—‡์„ ๊ฒ€์‚ฌํ•˜๋Š”์ง€ ์•Œ ์ˆ˜ ์—†๋‹ค. ์ปค์„œ ์ด๋™์„ ๊ทธ๋Œ€๋กœ ์žฌ์ƒํ•ด ์Šฌ๋กฏ๊ณผ ํŒŒ์ผ ์˜คํ”„์…‹์„ ๋‹ค์‹œ ์ด์–ด ๋ถ™์ด๋ฉด 656๋ฐ”์ดํŠธ ์ •๋‹ต ํŒŒ์ผ์ด ํ†ต์งธ๋กœ ๋ณต์›๋œ๋‹ค.
#dreamhack#ctf#reversing+5
2026-08-17#dreamhack +5
[๐Ÿฅ‰ Bronze 2] ๋ถ„๊ธฐ ๋ฏธ๋กœ ๋’ค์— ์ˆจ์€ ์ƒ์ˆ˜ ํ•œ ์ค„ โ€” DreamHack Labyrinth ํ’€์ด
blog

[๐Ÿฅ‰ Bronze 2] ๋ถ„๊ธฐ ๋ฏธ๋กœ ๋’ค์— ์ˆจ์€ ์ƒ์ˆ˜ ํ•œ ์ค„ โ€” DreamHack Labyrinth ํ’€์ด

14KB ์งœ๋ฆฌ stripped PIE ํ•˜๋‚˜๊ฐ€ ์ „๋ถ€์ธ ๋ฆฌ๋ฒ„์‹ฑ ๋ฌธ์ œ. ptrace ์•ˆํ‹ฐ๋””๋ฒ„๊น…๊ณผ ์‹œ๋“œ %7 ๋กœ ๊ฐˆ๋ผ์ง€๋Š” ๋ถ„๊ธฐ ๋ฏธ๋กœ๊ฐ€ ๊ฒน๊ฒน์ด ๊น”๋ ค ์žˆ์ง€๋งŒ, ์ •๋‹ต ์ž…๋ ฅ์€ .rodata ์˜ 32๋ฐ”์ดํŠธ๋ฅผ 0x30 ์œผ๋กœ XOR ํ•œ ๊ฒƒ์ด ์ „๋ถ€์˜€๋‹ค. flag ์ƒ์„ฑ๊ธฐ๊นŒ์ง€ ํŒŒ์ด์ฌ์œผ๋กœ ์žฌ๊ตฌํ˜„ํ•ด ๋ฐ”์ด๋„ˆ๋ฆฌ ์ถœ๋ ฅ๊ณผ ๋ฐ”์ดํŠธ ๋‹จ์œ„๋กœ ๋Œ€์กฐํ–ˆ๋‹ค.
#dreamhack#ctf#reversing+6
2026-08-20#dreamhack +5