[๐Ÿฅ‰ Bronze 2] .rodata 247๋ฐ”์ดํŠธ๊ฐ€ ์Šคํƒ VM ๋ฐ”์ดํŠธ์ฝ”๋“œ์˜€๋‹ค โ€” DreamHack SelfStatus ํ’€์ด

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

[๐Ÿฅ‰ Bronze 2] .rodata 247๋ฐ”์ดํŠธ๊ฐ€ ์Šคํƒ VM ๋ฐ”์ดํŠธ์ฝ”๋“œ์˜€๋‹ค โ€” DreamHack SelfStatus ํ’€์ด

ํ”„๋กœ๊ทธ๋žจ์ด ์ž๊ธฐ /proc/self/status ๋ฅผ ์ฝ์–ด TracerPid ๋กœ ๋””๋ฒ„๊ฑฐ๋ฅผ ์•Œ์•„์ฑ„๊ณ  ์กฐ์šฉํžˆ ์ฃฝ๋Š”๋‹ค. ์ง„์งœ ๊ฒ€์‚ฌ๋Š” .rodata ์— ๋ฐ•ํžŒ 247๋ฐ”์ดํŠธ๋ฅผ ๋„๋Š” ์Šคํƒ VM ์ด ๋งก๋Š”๋ฐ, ๊ทธ VM ์€ ์‚ฌ์šฉ์ž ์ž…๋ ฅ์„ ์•„์˜ˆ ์ณ๋‹ค๋ณด์ง€ ์•Š๊ณ  ์ •๋‹ต ๋ฌธ์ž์—ด์„ ์Šค์Šค๋กœ ์กฐ๋ฆฝํ•œ๋‹ค. ๊ทธ๋ž˜์„œ ์—ญ์‚ฐํ•  ๊ฒƒ์ด ์—†๋‹ค โ€” VM ๋งŒ ์˜ฎ๊ฒจ ์ ์œผ๋ฉด ๋๋‚œ๋‹ค.

๋ฌธ์ œ: DreamHack โ€” SelfStatus ๋ถ„๋ฅ˜: reversing ๋‚œ์ด๋„: ๐Ÿฅ‰ Bronze 2 FLAG: DH{S3lfSt4tus_VM_By7ec0d3}

๋ฌธ์ œ ์„ค๋ช…์€ ๋‘ ์ค„์ด ์ „๋ถ€๋‹ค. "Yet Another Self-Aware Flag Checker." ๊ทธ๋ฆฌ๊ณ  "Anti-Debugging VM."

๋ฐ›์€ ๊ฒƒ๋„ ํŒŒ์ผ ํ•˜๋‚˜๋ฟ์ด๋‹ค. 14KB์งœ๋ฆฌ stripped ELF ํ•˜๋‚˜. ์ด๋ฆ„๋ถ€ํ„ฐ SelfStatus ๋ผ์„œ ๋ญ˜ ์ฝ๋Š” ํ”„๋กœ๊ทธ๋žจ์ธ์ง€๋Š” ๋Œ€์ถฉ ์ง์ž‘์ด ๊ฐ€๋Š”๋ฐ, ์ •์ž‘ ์‹œ๊ฐ„์„ ์žก์•„๋จน๋Š” ์ชฝ์€ anti-debug ๊ฐ€ ์•„๋‹ˆ๋ผ ๊ทธ ๋’ค์— ์ˆจ์€ VM ์ด์—ˆ๋‹ค.

file extracted/prob && checksec --file=extracted/prob

file ๊ณผ checksec ์œผ๋กœ ํ™•์ธํ•œ prob ๋ฐ”์ด๋„ˆ๋ฆฌ โ€” x86-64 PIE, ์‹ฌ๋ณผ stripped, Partial RELRO ์— canary ์™€ NX ๊ฐ€ ์ผœ์ ธ ์žˆ๋‹ค
file ๊ณผ checksec ์œผ๋กœ ํ™•์ธํ•œ prob ๋ฐ”์ด๋„ˆ๋ฆฌ โ€” x86-64 PIE, ์‹ฌ๋ณผ stripped, Partial RELRO ์— canary ์™€ NX ๊ฐ€ ์ผœ์ ธ ์žˆ๋‹ค


๋ฌธ์ œ ๊ฐœ์š”

ํ•ญ๋ชฉ๋‚ด์šฉ
๋ฌธ์ œ๋ช…SelfStatus (DreamHack #1983)
๋‚œ์ด๋„๐Ÿฅ‰ Bronze 2
๋ถ„๋ฅ˜reversing
์ œ๊ณต ํŒŒ์ผprob โ€” 14,456๋ฐ”์ดํŠธ x86-64 PIE, stripped
์„œ๋ฒ„์—†์Œ (์˜คํ”„๋ผ์ธ ๋ฌธ์ œ)
๋ณดํ˜ธ ๊ธฐ๋ฒ•Partial RELRO ยท Canary ยท NX ยท PIE
ํ•ต์‹ฌ ๊ธฐ๋ฒ•procfs ๊ธฐ๋ฐ˜ anti-debug + .rodata ์ƒ์ฃผ ์Šคํƒ VM ๋ฐ”์ดํŠธ์ฝ”๋“œ

ํ’€์ด ํ๋ฆ„์€ ์งง๋‹ค. main ์€ ์„ธ ๊ฐ€์ง€๋งŒ ํ•œ๋‹ค.

  1. /proc/self/status ๋ฅผ ์ฝ์–ด TracerPid ๊ฐ€ 0 ์ด ์•„๋‹ˆ๋ฉด _exit(0) ์œผ๋กœ ์กฐ์šฉํžˆ ์ฃฝ๋Š”๋‹ค.
  2. ์ž…๋ ฅ์„ 127๋ฐ”์ดํŠธ๊นŒ์ง€ ๋ฐ›๊ณ  ๋์˜ ๊ฐœํ–‰๋งŒ ์ž˜๋ผ๋‚ธ๋‹ค.
  3. .rodata ์— ์žˆ๋Š” 247๋ฐ”์ดํŠธ๋ฅผ ์Šคํƒ VM ์œผ๋กœ ๋Œ๋ ค ๋งŒ๋“  ๋ฌธ์ž์—ด๊ณผ ๊ทธ ์ž…๋ ฅ์„ strcmp ํ•œ๋‹ค.

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

SelfStatus ์˜ main ํ๋ฆ„ ๋‹ค์ด์–ด๊ทธ๋žจ โ€” anti_debug ํ†ต๊ณผ ํ›„ ์ž…๋ ฅ์„ ์ฝ์ง€๋งŒ VM ์€ ๊ทธ ์ž…๋ ฅ๊ณผ ๋ฌด๊ด€ํ•˜๊ฒŒ ์ •๋‹ต์„ ์กฐ๋ฆฝํ•˜๊ณ  ๋งˆ์ง€๋ง‰ strcmp ์—์„œ๋งŒ ๋‘˜์ด ๋งŒ๋‚œ๋‹ค
SelfStatus ์˜ main ํ๋ฆ„ ๋‹ค์ด์–ด๊ทธ๋žจ โ€” anti_debug ํ†ต๊ณผ ํ›„ ์ž…๋ ฅ์„ ์ฝ์ง€๋งŒ VM ์€ ๊ทธ ์ž…๋ ฅ๊ณผ ๋ฌด๊ด€ํ•˜๊ฒŒ ์ •๋‹ต์„ ์กฐ๋ฆฝํ•˜๊ณ  ๋งˆ์ง€๋ง‰ strcmp ์—์„œ๋งŒ ๋‘˜์ด ๋งŒ๋‚œ๋‹ค



๐Ÿ”ฌ ์ •์ฐฐ โ€” import ์ผ๊ณฑ ๊ฐœ๊ฐ€ ์ „๋ถ€๋‹ค

stripped ๋ผ ์‹ฌ๋ณผ์€ ์—†์ง€๋งŒ, PLT ๋ฅผ ํ†ตํ•ด ๋ถ€๋ฅด๋Š” libc ํ•จ์ˆ˜๋Š” ๊ทธ๋Œ€๋กœ ๋‚จ๋Š”๋‹ค. ์—ฌ๊ธฐ๊ฐ€ ์ œ์ผ ์ •๋ณด๋Ÿ‰์ด ๋งŽ์€ ์ž๋ฆฌ๋‹ค.

readelf --dyn-syms -W extracted/prob | grep UND && strings -a -t x extracted/prob | grep -aE "proc/self|TracerPid|Enter flag|Correct|Wrong"

readelf ๋กœ ๋ฝ‘์€ UND ์‹ฌ๋ณผ ๋ชฉ๋ก๊ณผ strings ๊ฒฐ๊ณผ โ€” open read close write strcmp strstr _exit ์ผ๊ณฑ ๊ฐœ๋ฟ์ด๊ณ  ๋ฌธ์ž์—ด์—๋Š” proc self status ์™€ TracerPid ๊ฐ€ ๋ณด์ธ๋‹ค
readelf ๋กœ ๋ฝ‘์€ UND ์‹ฌ๋ณผ ๋ชฉ๋ก๊ณผ strings ๊ฒฐ๊ณผ โ€” open read close write strcmp strstr _exit ์ผ๊ณฑ ๊ฐœ๋ฟ์ด๊ณ  ๋ฌธ์ž์—ด์—๋Š” proc self status ์™€ TracerPid ๊ฐ€ ๋ณด์ธ๋‹ค

open ยท read ยท close ยท write ยท strcmp ยท strstr ยท _exit. ์ด๊ฒŒ ์ „๋ถ€๋‹ค.

์—ฌ๊ธฐ์„œ ์ด๋ฏธ ๋งŽ์€ ๊ฒŒ ์ •ํ•ด์ง„๋‹ค. printf ๋„ malloc ๋„ ์—†์œผ๋‹ˆ ์ถœ๋ ฅ์€ ์ „๋ถ€ write(1, ...) ์ด๊ณ , ํž™์€ ์•ˆ ์“ด๋‹ค. ๊ทธ๋ฆฌ๊ณ  strstr ์ด ์žˆ๋‹ค๋Š” ๊ฑด ์–ด๋”˜๊ฐ€์—์„œ ๋ฌธ์ž์—ด ์•ˆ์„ ๋’ค์ง„๋‹ค๋Š” ๋œป์ธ๋ฐ, ํ›„๋ณด๋Š” ๋ฌธ์ž์—ด ๋ชฉ๋ก์— ํ•˜๋‚˜๋ฟ์ด๋‹ค โ€” TracerPid:.

ํŒŒ์ผ๋ช…์ด SelfStatus ์ธ ์ด์œ ๋„ ์—ฌ๊ธฐ์„œ ๋‚˜์˜จ๋‹ค. /proc/self/status ๋ฅผ ์ฝ๋Š”๋‹ค.

์ด์ œ ์ƒ์ˆ˜ ์˜์—ญ์„ ํ†ต์งธ๋กœ ๋ณธ๋‹ค.

objdump -s -j .rodata extracted/prob

objdump -s ๋กœ ๋คํ”„ํ•œ .rodata โ€” 0x2020 ๋ถ€ํ„ฐ 0x2116 ๊นŒ์ง€ ee a1 a3 f0 ์ด ๋ฐ˜๋ณต๋˜๋Š” ์ •์ฒด๋ถˆ๋ช… ๋ฐ”์ดํŠธ์—ด์ด ์ด์–ด์ง€๊ณ  ๊ทธ ๋’ค์— ๋ฌธ์ž์—ด๋“ค์ด ๋ถ™์–ด ์žˆ๋‹ค
objdump -s ๋กœ ๋คํ”„ํ•œ .rodata โ€” 0x2020 ๋ถ€ํ„ฐ 0x2116 ๊นŒ์ง€ ee a1 a3 f0 ์ด ๋ฐ˜๋ณต๋˜๋Š” ์ •์ฒด๋ถˆ๋ช… ๋ฐ”์ดํŠธ์—ด์ด ์ด์–ด์ง€๊ณ  ๊ทธ ๋’ค์— ๋ฌธ์ž์—ด๋“ค์ด ๋ถ™์–ด ์žˆ๋‹ค

0x2117 ๋ถ€ํ„ฐ๋Š” ์•„๊นŒ ๋ณธ ๋ฌธ์ž์—ด๋“ค์ด๋‹ค. ๋ฌธ์ œ๋Š” ๊ทธ ์•ž. 0x2020 ๋ถ€ํ„ฐ 0x2116 ๊นŒ์ง€ 247๋ฐ”์ดํŠธ๊ฐ€ ์•„์Šคํ‚ค๋„ ์•„๋‹ˆ๊ณ  ํฌ์ธํ„ฐ ๋ฐฐ์—ด๋„ ์•„๋‹Œ ๋ฌด์–ธ๊ฐ€๋กœ ์ฑ„์›Œ์ ธ ์žˆ๋‹ค.

๋ˆˆ์— ๋„๋Š” ๊ทœ์น™์ด ํ•˜๋‚˜ ์žˆ๋‹ค. ee ๊ฐ€ ์œ ๋‚œํžˆ ๋งŽ๊ณ , a1 ยท a3 ยท f0 ์ด ์งง์€ ๊ฐ„๊ฒฉ์œผ๋กœ ๋˜ํ’€์ด๋œ๋‹ค. a342f0 ์ด๋ผ๋Š” ์„ธ ๋ฐ”์ดํŠธ ๋ฌถ์Œ์ด ๊ณ„์† ๋ณด์ธ๋‹ค. ์ด๊ฑด ๋ฐ์ดํ„ฐ๋ผ๊ธฐ๋ณด๋‹ค ๋ช…๋ น ์ŠคํŠธ๋ฆผ์ฒ˜๋Ÿผ ์ƒ๊ฒผ๋‹ค.



๐Ÿงฉ ๋ฐฐ๊ฒฝ โ€” ๋ฆฌ๋ˆ…์Šค์—์„œ "์ง€๊ธˆ ๋ˆ„๊ฐ€ ๋‚˜๋ฅผ ์ถ”์  ์ค‘์ธ๊ฐ€"

๋ฆฌ๋ˆ…์Šค์—์„œ ํ”„๋กœ์„ธ์Šค๋Š” ์ž๊ธฐ ์ž์‹ ์— ๋Œ€ํ•œ ๊ฑฐ์˜ ๋ชจ๋“  ๊ฒƒ์„ ํŒŒ์ผ๋กœ ์ฝ์„ ์ˆ˜ ์žˆ๋‹ค. /proc/self/ ์•„๋ž˜๊ฐ€ ๊ทธ ์ฐฝ๊ตฌ๋‹ค.

๊ทธ์ค‘ status ์—๋Š” TracerPid ๋ผ๋Š” ์ค„์ด ์žˆ๋‹ค. ptrace ๋กœ ์ด ํ”„๋กœ์„ธ์Šค์— ๋ถ™์–ด ์žˆ๋Š” ์ถ”์ ์ž์˜ PID ๊ฐ€ ์ ํžˆ๊ณ , ์•„๋ฌด๋„ ์•ˆ ๋ถ™์—ˆ์œผ๋ฉด 0 ์ด๋‹ค.

์ง์ ‘ ๋‘ ๊ฒฝ์šฐ๋ฅผ ๋‚˜๋ž€ํžˆ ์ฐ์–ด ๋ณด๋ฉด ์ด๋ ‡๋‹ค.

#!/usr/bin/env bash
# TracerPid ๊ฐ€ ์‹ค์ œ๋กœ ๋ฌด์—‡์„ ๋‹ด๋Š”์ง€ ๋‘ ๊ฒฝ์šฐ๋กœ ๋น„๊ตํ•œ๋‹ค.
#   โ‘  ์•„๋ฌด๋„ ์•ˆ ๋ถ™์—ˆ์„ ๋•Œ  โ‘ก gdb ๊ฐ€ ๋ถ™์–ด ์žˆ์„ ๋•Œ
echo "[1] ์•„๋ฌด๋„ ์•ˆ ๋ถ™์€ ์ƒํƒœ (์ด ์…ธ ์ž์‹ )"
grep TracerPid /proc/self/status
 
echo
echo "[2] gdb ๋กœ prob ์„ ๋ถ™์žก์•„ ๋‘” ์ƒํƒœ โ€” ๊ทธ ํ”„๋กœ์„ธ์Šค์˜ status ๋ฅผ ๋ณธ๋‹ค"
gdb -q -batch -ex starti \
    -ex 'shell grep TracerPid /proc/$(pgrep -n prob)/status' \
    -ex kill --args ./extracted/prob
./tracerpid_demo.sh

tracerpid_demo.sh ์‹คํ–‰ ๊ฒฐ๊ณผ โ€” ํ‰์†Œ์—๋Š” TracerPid ๊ฐ€ 0 ์ด์ง€๋งŒ gdb ๋กœ ๋ถ™์žก์•„ ๋‘” ํ”„๋กœ์„ธ์Šค์˜ status ์—๋Š” gdb ์˜ PID ๊ฐ€ ๊ทธ๋Œ€๋กœ ์ ํ˜€ ์žˆ๋‹ค
tracerpid_demo.sh ์‹คํ–‰ ๊ฒฐ๊ณผ โ€” ํ‰์†Œ์—๋Š” TracerPid ๊ฐ€ 0 ์ด์ง€๋งŒ gdb ๋กœ ๋ถ™์žก์•„ ๋‘” ํ”„๋กœ์„ธ์Šค์˜ status ์—๋Š” gdb ์˜ PID ๊ฐ€ ๊ทธ๋Œ€๋กœ ์ ํ˜€ ์žˆ๋‹ค

[2] ์—์„œ ๋‚˜์˜จ ์ˆซ์ž๋Š” ๋ถ™์–ด ์žˆ๋Š” gdb ์˜ PID ๋‹ค. ํ”„๋กœ์„ธ์Šค๊ฐ€ ์ž๊ธฐ ํŒŒ์ผ ํ•˜๋‚˜๋งŒ ์ฝ์–ด๋„ ์ถ”์ ์ž์˜ ์ •์ฒด๊นŒ์ง€ ์•Œ ์ˆ˜ ์žˆ๋‹ค.

ptrace(PTRACE_TRACEME) ๋ฅผ ์ž๊ธฐ๊ฐ€ ๋จผ์ € ๊ฑธ์–ด ๋‘๋Š” ๊ณ ์ „์ ์ธ anti-debug ์™€ ๋น„๊ตํ•˜๋ฉด ์„ฑ๊ฒฉ์ด ๋‹ค๋ฅด๋‹ค. ๊ทธ ๋ฐฉ์‹์€ "๋””๋ฒ„๊ฑฐ๋ณด๋‹ค ๋จผ์ € ์ž๋ฆฌ๋ฅผ ์ฐจ์ง€ํ•œ๋‹ค"๋Š” ์„ ์ ์ด๊ณ , ์ด์ชฝ์€ ๊ทธ๋ƒฅ ๋ฌผ์–ด๋ณธ๋‹ค. ์ฝ”๋“œ๋Š” ํ›จ์”ฌ ์งง๊ณ , ๋Œ€์‹  ์šฐํšŒ๋„ ํ›จ์”ฌ ์‰ฝ๋‹ค. ํŒŒ์ผ ํ•˜๋‚˜๋งŒ ๋‹ค๋ฅธ ๊ฑธ๋กœ ๋ฐ”๊ฟ”์น˜๊ธฐํ•˜๋ฉด ๋˜๋‹ˆ๊นŒ.

gdb ๋“  strace ๋“  ltrace ๋“  ์ „๋ถ€ ptrace ์œ„์— ์„œ ์žˆ์œผ๋ฏ€๋กœ ์…‹ ๋‹ค ๋˜‘๊ฐ™์ด ๊ฑธ๋ฆฐ๋‹ค.


๐Ÿ›ก๏ธ anti_debug() ๋ฅผ ๋ช…๋ น ๋‹จ์œ„๋กœ ์ฝ๋Š”๋‹ค

0x11a9 ์—์„œ ์‹œ์ž‘ํ•˜๋Š” ํ•จ์ˆ˜๊ฐ€ ๊ทธ ๊ฒ€์‚ฌ๋‹ค. ์ฝ๊ธฐ ํŽธํ•˜๊ฒŒ objdump ์ถœ๋ ฅ์— ์ฃผ์„์„ ์–น์—ˆ๋‹ค. ์ฃผ์„์€ ๋„๊ตฌ๊ฐ€ ์ฐ์–ด ์ฃผ๋Š” ๊ฒŒ ์•„๋‹ˆ๋ผ ๋‚ด๊ฐ€ sed ๋กœ ๋ง๋ถ™์ธ ๊ฒƒ์ด๊ณ , ๊ทœ์น™ ํŒŒ์ผ์€ ๋ฌธ์ œ ํด๋”์— annot_antidbg.sed ๋กœ ๋‚จ๊ฒผ๋‹ค.

s|# 2117 .*|&   <-- "/proc/self/status"|
s|# 2129 .*|&   <-- "TracerPid:"|
s|call.*<open@plt>|&   <-- open(path, O_RDONLY)|
s|mov    edx,0x1ff|&   <-- ์ตœ๋Œ€ 511๋ฐ”์ดํŠธ๋งŒ ์ฝ๋Š”๋‹ค|
s|call.*<read@plt>|&   <-- read(fd, buf, 511)|
s|call.*<strstr@plt>|&   <-- strstr(buf, "TracerPid:")|
s|add    QWORD PTR \[rbp-0x220\],0xa|&   <-- ํฌ์ธํ„ฐ๋ฅผ "TracerPid:" 10๊ธ€์ž๋งŒํผ ์ „์ง„|
s|cmp    al,0x20|&   <-- ๊ณต๋ฐฑ ๊ฑด๋„ˆ๋›ฐ๊ธฐ|
s|cmp    al,0x9|&   <-- ํƒญ ๊ฑด๋„ˆ๋›ฐ๊ธฐ|
s|cmp    al,0x30|&   <-- ์ฒซ ๊ธ€์ž๊ฐ€ '0' ์ธ๊ฐ€|
s|mov    eax,0x1$|&   <-- '0' ์ด ์•„๋‹ˆ๋ฉด 1(=์ถ”์ ๋‹นํ•˜๋Š” ์ค‘) ๋ฐ˜ํ™˜|
objdump -d -M intel --start-address=0x11c3 --stop-address=0x1239 extracted/prob | sed -f annot_antidbg.sed

objdump ์ •์  ๋ถ„์„ โ€” anti_debug ์•ž๋ถ€๋ถ„์ด proc self status ๋ฅผ ์—ด๊ณ  511๋ฐ”์ดํŠธ๋ฅผ ์ฝ์€ ๋’ค close ํ•˜๋Š” ํ๋ฆ„์ด ๊ทธ๋Œ€๋กœ ๋ณด์ธ๋‹ค
objdump ์ •์  ๋ถ„์„ โ€” anti_debug ์•ž๋ถ€๋ถ„์ด proc self status ๋ฅผ ์—ด๊ณ  511๋ฐ”์ดํŠธ๋ฅผ ์ฝ์€ ๋’ค close ํ•˜๋Š” ํ๋ฆ„์ด ๊ทธ๋Œ€๋กœ ๋ณด์ธ๋‹ค

๋ฒ„ํผ๋Š” ์Šคํƒ์˜ rbp-0x210, ํฌ๊ธฐ๋Š” 0x1ff = 511๋ฐ”์ดํŠธ. ์ฝ์€ ๊ธธ์ด๊ฐ€ 0 ์ดํ•˜๋ฉด ๊ทธ๋ƒฅ 0 ์„ ๋ฐ˜ํ™˜ํ•˜๊ณ  ๋๋‚œ๋‹ค. ์ฆ‰ ํŒŒ์ผ์„ ๋ชป ์ฝ์œผ๋ฉด "์ถ”์  ์•ˆ ๋‹นํ•จ"์œผ๋กœ ์นœ๋‹ค. ๋’ค์—์„œ ์ด ์„ฑ์งˆ์„ ๊ทธ๋Œ€๋กœ ์ด์šฉํ•œ๋‹ค.

๋’ท๋ถ€๋ถ„์ด ํŒ์ •์ด๋‹ค.

objdump -d -M intel --start-address=0x125c --stop-address=0x12cf extracted/prob | sed -f annot_antidbg.sed

objdump ์ •์  ๋ถ„์„ โ€” strstr ๋กœ TracerPid ๋ฅผ ์ฐพ์•„ 10๋ฐ”์ดํŠธ ์ „์ง„ํ•œ ๋’ค ๊ณต๋ฐฑ๊ณผ ํƒญ์„ ๊ฑด๋„ˆ๋›ฐ๊ณ  ์ฒซ ๊ธ€์ž๊ฐ€ 0x30 ์ธ์ง€ ๋น„๊ตํ•˜๋Š” ๋ถ€๋ถ„
objdump ์ •์  ๋ถ„์„ โ€” strstr ๋กœ TracerPid ๋ฅผ ์ฐพ์•„ 10๋ฐ”์ดํŠธ ์ „์ง„ํ•œ ๋’ค ๊ณต๋ฐฑ๊ณผ ํƒญ์„ ๊ฑด๋„ˆ๋›ฐ๊ณ  ์ฒซ ๊ธ€์ž๊ฐ€ 0x30 ์ธ์ง€ ๋น„๊ตํ•˜๋Š” ๋ถ€๋ถ„

C ๋กœ ์˜ฎ๊ธฐ๋ฉด ์ด ์ •๋„๋‹ค.

int anti_debug(void)
{
    char buf[512];
    int fd = open("/proc/self/status", O_RDONLY);
    if (fd < 0) return 0;                       /* ๋ชป ์—ด๋ฉด ํ†ต๊ณผ */
 
    ssize_t n = read(fd, buf, 0x1ff);
    close(fd);
    if (n <= 0) return 0;                       /* ๋ชป ์ฝ์–ด๋„ ํ†ต๊ณผ */
    buf[n] = 0;
 
    char *p = strstr(buf, "TracerPid:");
    if (!p) return 0;                           /* ๊ทธ ์ค„์ด ์—†์–ด๋„ ํ†ต๊ณผ */
    p += 10;
    while (*p == ' ' || *p == '\t') p++;
 
    return (*p == '0') ? 0 : 1;
}

๋น ์ ธ๋‚˜๊ฐˆ ๊ตฌ๋ฉ์ด ์„ธ ๊ตฐ๋ฐ๋‚˜ ์—ด๋ ค ์žˆ๋‹ค. ํŒŒ์ผ์ด ์—†์–ด๋„, ์ฝ๊ธฐ๊ฐ€ ์‹คํŒจํ•ด๋„, TracerPid: ๋ผ๋Š” ๋ฌธ์ž์—ด์ด ์•„์˜ˆ ์—†์–ด๋„ ์ „๋ถ€ "์ •์ƒ"์œผ๋กœ ํ†ต๊ณผํ•œ๋‹ค. ๊ฒ€์‚ฌ๋ฅผ ๋งŒ๋“ค ๋•Œ ์‹คํŒจ๋ฅผ ์•ˆ์ „ํ•œ ์ชฝ์œผ๋กœ ๋–จ์–ด๋œจ๋ฆฐ ์…ˆ์ธ๋ฐ, anti-debug ๋กœ์„œ๋Š” ์ •๋ฐ˜๋Œ€ ๋ฐฉํ–ฅ์ด๋‹ค.

์‹ค์ œ๋กœ ๋„๋Š”์ง€๋Š” strace ๋กœ ๋ฐ”๋กœ ๋ณด์ธ๋‹ค. ๊ทธ๋Ÿฐ๋ฐ strace ์ž์‹ ์ด ptrace ๋กœ ๋ถ™๋Š” ๋„๊ตฌ๋ผ์„œ, ๋ถ™๋Š” ์ˆœ๊ฐ„ ๊ฒ€์‚ฌ์— ๊ฑธ๋ฆฐ๋‹ค.

strace -f -e trace=openat,open,read,write,exit_group ./extracted/prob

strace ๋Ÿฐํƒ€์ž„ ํ™•์ธ โ€” proc self status ๋ฅผ 511๋ฐ”์ดํŠธ ์ฝ์ž๋งˆ์ž exit_group 0 ์œผ๋กœ ์ข…๋ฃŒํ•˜๊ณ  Enter flag ์ถœ๋ ฅ์€ ์•„์˜ˆ ๋‚˜์˜ค์ง€ ์•Š๋Š”๋‹ค
strace ๋Ÿฐํƒ€์ž„ ํ™•์ธ โ€” proc self status ๋ฅผ 511๋ฐ”์ดํŠธ ์ฝ์ž๋งˆ์ž exit_group 0 ์œผ๋กœ ์ข…๋ฃŒํ•˜๊ณ  Enter flag ์ถœ๋ ฅ์€ ์•„์˜ˆ ๋‚˜์˜ค์ง€ ์•Š๋Š”๋‹ค

/proc/self/status ๋ฅผ 511๋ฐ”์ดํŠธ ์ฝ๊ณ  ๊ณง์žฅ exit_group(0). write ๋Š” ํ•œ ๋ฒˆ๋„ ์•ˆ ๋‚˜์˜จ๋‹ค. ํ”„๋กฌํ”„ํŠธ์กฐ์ฐจ ๋ชป ์ฐ๊ณ  ์ฃฝ์€ ๊ฒƒ์ด๋‹ค. ๊ฒ€์‚ฌ๊ฐ€ ์‹ค์ œ๋กœ ๋™์ž‘ํ•œ๋‹ค๋Š” ์ฆ๊ฑฐ๋กœ๋Š” ์ด๋ณด๋‹ค ๊น”๋”ํ•œ ๊ฒŒ ์—†๋‹ค.

โ–ถ๐Ÿ› ํ•จ์ • โ€” ๋””๋ฒ„๊ฑฐ๋กœ ๋ถ™์œผ๋ฉด ์•„๋ฌด ์ผ๋„ ์•ˆ ์ผ์–ด๋‚œ๋‹ค

์ •์  ๋ถ„์„ ์—†์ด ๋จผ์ € gdb ๋กœ ๋ถ™์–ด ๋ณด๋ฉด ์ด๋ ‡๊ฒŒ ๋œ๋‹ค.

gdb -q -batch -ex run --args ./extracted/prob

gdb -batch ์‹คํ–‰ ๊ฒฐ๊ณผ โ€” Enter flag ํ”„๋กฌํ”„ํŠธ๋„ ์—†์ด Inferior 1 exited normally ๋งŒ ์ฐํžˆ๊ณ  ๋๋‚œ๋‹ค
gdb -batch ์‹คํ–‰ ๊ฒฐ๊ณผ โ€” Enter flag ํ”„๋กฌํ”„ํŠธ๋„ ์—†์ด Inferior 1 exited normally ๋งŒ ์ฐํžˆ๊ณ  ๋๋‚œ๋‹ค

exited normally ๋‹ค. ํฌ๋ž˜์‹œ๋„ ์•„๋‹ˆ๊ณ  ์—๋Ÿฌ ๋ฉ”์‹œ์ง€๋„ ์—†๋‹ค. ์ข…๋ฃŒ ์ฝ”๋“œ๊นŒ์ง€ 0 ์ด๋ผ "๋””๋ฒ„๊ฑฐ๊ฐ€ ๋ญ˜ ์ž˜๋ชปํ–ˆ๋‚˜", "๋ฐ”์ด๋„ˆ๋ฆฌ๊ฐ€ ๊นจ์กŒ๋‚˜" ์ชฝ์„ ๋จผ์ € ์˜์‹ฌํ•˜๊ฒŒ ๋œ๋‹ค.

_exit(0) ์„ ๊ณ ๋ฅธ ๊ฒŒ ์ด ๋ฌธ์ œ์˜ ์–„๋ฏธ์šด ๋ถ€๋ถ„์ด๋‹ค. _exit(1) ์ด๋‚˜ abort() ์˜€๋‹ค๋ฉด ๋น„์ •์ƒ ์ข…๋ฃŒ๊ฐ€ ๋ˆˆ์— ๋„์–ด์„œ ๋ฐ”๋กœ anti-debug ๋ฅผ ๋– ์˜ฌ๋ ธ์„ ๊ฒƒ์ด๋‹ค. ์•„๋ฌด ์†Œ๋ฆฌ๋„ ์•ˆ ๋‚ด๋Š” ์‹คํŒจ๊ฐ€ ์ œ์ผ ์ฐพ๊ธฐ ์–ด๋ ต๋‹ค.

ํ„ฐ๋ฏธ๋„์—์„œ ๊ทธ๋ƒฅ ./prob ๋ฅผ ์‹คํ–‰ํ•˜๋ฉด ๋ฉ€์ฉกํžˆ ํ”„๋กฌํ”„ํŠธ๊ฐ€ ๋œจ๋Š”๋ฐ ๋””๋ฒ„๊ฑฐ ์•ˆ์—์„œ๋งŒ ์กฐ์šฉํžˆ ์ฃฝ๋Š”๋‹ค๋ฉด, ๊ทธ ์‹œ์ ์— /proc/self/status ยท ptrace ยท getppid ์ชฝ์„ ๋จผ์ € ๋’ค์ง€๋Š” ๊ฒŒ ๋งž๋‹ค.



๐Ÿ’ฃ ํ•ต์‹ฌ โ€” .rodata 247๋ฐ”์ดํŠธ๋Š” ์Šคํƒ VM ๋ฐ”์ดํŠธ์ฝ”๋“œ๋‹ค

main ์€ anti-debug ๋ฅผ ํ†ต๊ณผํ•œ ๋’ค write(1, "Enter flag: ", 13) ์œผ๋กœ ํ”„๋กฌํ”„ํŠธ๋ฅผ ์ฐ๊ณ  read(0, buf, 0x7f) ๋กœ ์ž…๋ ฅ์„ ๋ฐ›๋Š”๋‹ค. ๊ทธ๋ฆฌ๊ณ  0x12e5 ์˜ ํ•จ์ˆ˜๋ฅผ ์ด๋ ‡๊ฒŒ ๋ถ€๋ฅธ๋‹ค.

15f9:  lea    rax,[rbp-0x90]        ; 3๋ฒˆ์งธ ์ธ์ž: ์ถœ๋ ฅ ๋ฒ„ํผ
1600:  mov    rdx,rax
1603:  mov    esi,0xf7              ; 2๋ฒˆ์งธ ์ธ์ž: 247 (= 0x2116 - 0x2020 + 1)
1608:  lea    rax,[rip+0xa11]       ; 1๋ฒˆ์งธ ์ธ์ž: 0x2020 โ€” .rodata ์˜ ๊ทธ ๋ฐ”์ดํŠธ์—ด
160f:  mov    rdi,rax
1612:  call   12e5                  ; vm(code, len, out)
1617:  lea    rdx,[rbp-0x110]       ; ์‚ฌ์šฉ์ž ์ž…๋ ฅ
161e:  lea    rax,[rbp-0x90]        ; VM ์ถœ๋ ฅ
1625:  mov    rsi,rdx
1628:  mov    rdi,rax
162b:  call   1080 <strcmp@plt>

์ธ์ž ์…‹ ์–ด๋””์—๋„ ์‚ฌ์šฉ์ž ์ž…๋ ฅ์ด ์—†๋‹ค. ์ž…๋ ฅ์€ 0x1617 ์—์„œ strcmp ๋กœ ๋„˜์–ด๊ฐˆ ๋•Œ ์ฒ˜์Œ ๋“ฑ์žฅํ•œ๋‹ค.

0x12e5 ํ•จ์ˆ˜ ์•ˆ์„ ๋ณด๋ฉด ์™œ ์ด๊ฒŒ VM ์ธ์ง€ ๋ฐ”๋กœ ๋“œ๋Ÿฌ๋‚œ๋‹ค. ์—ฌ๊ธฐ์„œ๋„ objdump ์ถœ๋ ฅ์— sed ๋กœ ์ฃผ์„์„ ์–น์—ˆ๊ณ , ๊ทœ์น™์€ annot_vm.sed ์— ์žˆ๋‹ค.

s|cmp    BYTE PTR \[rbp-0xa9\],0xa1|&   <-- PUSH imm|
s|cmp    BYTE PTR \[rbp-0xa9\],0xa2|&   <-- POP|
s|cmp    BYTE PTR \[rbp-0xa9\],0xa3|&   <-- XOR imm|
s|cmp    BYTE PTR \[rbp-0xa9\],0xa4|&   <-- ADD imm|
s|cmp    BYTE PTR \[rbp-0xa9\],0xa5|&   <-- SKIP (์˜คํผ๋žœ๋“œ 1๋ฐ”์ดํŠธ ๋ฒ„๋ฆผ)|
s|cmp    BYTE PTR \[rbp-0xa9\],0xee|&   <-- SKIP (0xa5 ์™€ ์™„์ „ํžˆ ๊ฐ™์€ ๋™์ž‘)|
s|cmp    BYTE PTR \[rbp-0xa9\],0xf0|&   <-- OUT (pop ํ•ด์„œ ์ถœ๋ ฅ ๋ฒ„ํผ๋กœ)|
s|cmp    BYTE PTR \[rbp-0xa9\],0xff|&   <-- HALT|
s|mov    QWORD PTR \[rbp-0x98\],rdx|&   <-- pc ๊ฐฑ์‹ |
s|mov    BYTE PTR \[rbp-0xa9\],al|&   <-- op = code\[pc++\]|
s|mov    BYTE PTR \[rbp+rax\*1-0x90\],dl|&   <-- stack\[sp++\] = code\[pc++\]|
s|add    QWORD PTR \[rbp-0x98\],0x1$|&   <-- pc += 1 (์˜คํผ๋žœ๋“œ๋ฅผ ์‚ผํ‚ค๊ธฐ๋งŒ ํ•œ๋‹ค)|
s|sub    QWORD PTR \[rbp-0xa8\],0x1$|&   <-- sp -= 1|
s|mov    BYTE PTR \[rax\],dl|&   <-- out\[oi++\] = stack\[sp\]|

๋จผ์ € ๋ฃจํ”„์˜ ๋จธ๋ฆฌ๋‹ค.

objdump -d -M intel --start-address=0x133a --stop-address=0x13a6 extracted/prob | sed -f annot_vm.sed

objdump ์ •์  ๋ถ„์„ โ€” ๋ฐ”์ดํŠธ์ฝ”๋“œ ์ธํ„ฐํ”„๋ฆฌํ„ฐ์˜ fetch ๋ถ€๋ถ„๊ณผ PUSH ํ•ธ๋“ค๋Ÿฌ. pc ๋ฅผ ํ•˜๋‚˜ ์˜ฌ๋ ค opcode ๋ฅผ ์ฝ๊ณ  ๋‹ค์‹œ ํ•˜๋‚˜ ์˜ฌ๋ ค ์˜คํผ๋žœ๋“œ๋ฅผ ์Šคํƒ์— ์Œ“๋Š”๋‹ค
objdump ์ •์  ๋ถ„์„ โ€” ๋ฐ”์ดํŠธ์ฝ”๋“œ ์ธํ„ฐํ”„๋ฆฌํ„ฐ์˜ fetch ๋ถ€๋ถ„๊ณผ PUSH ํ•ธ๋“ค๋Ÿฌ. pc ๋ฅผ ํ•˜๋‚˜ ์˜ฌ๋ ค opcode ๋ฅผ ์ฝ๊ณ  ๋‹ค์‹œ ํ•˜๋‚˜ ์˜ฌ๋ ค ์˜คํผ๋žœ๋“œ๋ฅผ ์Šคํƒ์— ์Œ“๋Š”๋‹ค

์ง€์—ญ๋ณ€์ˆ˜ ์…‹์ด VM ์ƒํƒœ ์ „๋ถ€๋‹ค.

์Šคํƒ ์Šฌ๋กฏ์—ญํ• 
rbp-0x98pc โ€” ๋ฐ”์ดํŠธ์ฝ”๋“œ ์•ˆ์—์„œ์˜ ์œ„์น˜
rbp-0xa8sp โ€” ๊ฐ’ ์Šคํƒ์˜ ๋†’์ด
rbp-0x90 ์ดํ•˜๊ฐ’ ์Šคํƒ (๋ฐ”์ดํŠธ ๋‹จ์œ„)
rbp-0xa0์ถœ๋ ฅ ๋ฒ„ํผ์— ์“ด ๊ฐœ์ˆ˜

๋””์ŠคํŒจ์น˜๋Š” ์ ํ”„ ํ…Œ์ด๋ธ”์ด ์•„๋‹ˆ๋ผ cmp ๋ฅผ ์ค„์ค„์ด ๋Š˜์–ด๋†“์€ ํ˜•ํƒœ๋ผ์„œ, ๊ทธ ๋น„๊ต๋ฌธ๋งŒ ๋ฝ‘์œผ๋ฉด ๋ช…๋ น์–ด ์ง‘ํ•ฉ์ด ํ•œ ํ™”๋ฉด์— ๋“ค์–ด์˜จ๋‹ค.

objdump -d -M intel extracted/prob | grep -E "cmp +BYTE PTR \[rbp-0xa9\]" | sed -f annot_vm.sed

objdump ์™€ grep ์œผ๋กœ ๋ฝ‘์€ VM opcode ๋””์ŠคํŒจ์น˜ ์ฒด์ธ โ€” a1 a2 a3 a4 a5 ee f0 ff ์—ฌ๋Ÿ ๊ฐœ์˜ ๋น„๊ต๋ฌธ์ด ์ˆœ์„œ๋Œ€๋กœ ๋‚˜์˜จ๋‹ค
objdump ์™€ grep ์œผ๋กœ ๋ฝ‘์€ VM opcode ๋””์ŠคํŒจ์น˜ ์ฒด์ธ โ€” a1 a2 a3 a4 a5 ee f0 ff ์—ฌ๋Ÿ ๊ฐœ์˜ ๋น„๊ต๋ฌธ์ด ์ˆœ์„œ๋Œ€๋กœ ๋‚˜์˜จ๋‹ค

์ •๋ฆฌํ•˜๋ฉด ์ด๋ ‡๋‹ค.

opcode๋™์ž‘์˜คํผ๋žœ๋“œ
0xa1stack[sp++] = imm1๋ฐ”์ดํŠธ
0xa2sp ๊ฐ€ 0 ์ด ์•„๋‹ˆ๋ฉด sp--์—†์Œ
0xa3์Šคํƒ ๋งจ ์œ„๋ฅผ imm ๊ณผ XOR1๋ฐ”์ดํŠธ
0xa4์Šคํƒ ๋งจ ์œ„์— imm ์„ ๋”ํ•จ1๋ฐ”์ดํŠธ
0xa5์•„๋ฌด ์ผ๋„ ์•ˆ ํ•จ1๋ฐ”์ดํŠธ (๋ฒ„๋ฆผ)
0xee์•„๋ฌด ์ผ๋„ ์•ˆ ํ•จ1๋ฐ”์ดํŠธ (๋ฒ„๋ฆผ)
0xf0sp-- ํ›„ ๊ทธ ๊ฐ’์„ ์ถœ๋ ฅ ๋ฒ„ํผ๋กœ์—†์Œ
0xff์ข…๋ฃŒ์—†์Œ

0xa5 ์™€ 0xee ๋‘ ๊ฐœ๊ฐ€ ๊ฐ™์€ ์ผ์„ ํ•œ๋‹ค. ๋‘˜ ๋‹ค pc ๋ฅผ 1 ์˜ฌ๋ฆฌ๊ธฐ๋งŒ ํ•˜๋Š”๋ฐ, fetch ๋‹จ๊ณ„์—์„œ ์ด๋ฏธ pc++ ๋ฅผ ํ–ˆ์œผ๋‹ˆ ๋‹ค์Œ 1๋ฐ”์ดํŠธ๋ฅผ ์˜คํผ๋žœ๋“œ๋กœ ์‚ผ์ผœ์„œ ๋ฒ„๋ฆฌ๋Š” ๋™์ž‘์ด๋‹ค. ์ด๊ฒŒ ์ด ๋ฌธ์ œ์˜ ๋‚œ๋…ํ™” ์žฅ์น˜๋‹ค.

๋งˆ์ง€๋ง‰์œผ๋กœ ์ถœ๋ ฅ ํ•ธ๋“ค๋Ÿฌ๋ฅผ ํ™•์ธํ•œ๋‹ค.

objdump -d -M intel --start-address=0x14a1 --stop-address=0x1505 extracted/prob | sed -f annot_vm.sed

objdump ์ •์  ๋ถ„์„ โ€” 0xee SKIP ํ•ธ๋“ค๋Ÿฌ์™€ 0xf0 OUT ํ•ธ๋“ค๋Ÿฌ. sp ๋ฅผ ํ•˜๋‚˜ ๋‚ด๋ฆฐ ๋’ค ๊ทธ ์ž๋ฆฌ ๊ฐ’์„ ์„ธ ๋ฒˆ์งธ ์ธ์ž๊ฐ€ ๊ฐ€๋ฆฌํ‚ค๋Š” ์ถœ๋ ฅ ๋ฒ„ํผ์— ์ˆœ์„œ๋Œ€๋กœ ๊ธฐ๋กํ•œ๋‹ค
objdump ์ •์  ๋ถ„์„ โ€” 0xee SKIP ํ•ธ๋“ค๋Ÿฌ์™€ 0xf0 OUT ํ•ธ๋“ค๋Ÿฌ. sp ๋ฅผ ํ•˜๋‚˜ ๋‚ด๋ฆฐ ๋’ค ๊ทธ ์ž๋ฆฌ ๊ฐ’์„ ์„ธ ๋ฒˆ์งธ ์ธ์ž๊ฐ€ ๊ฐ€๋ฆฌํ‚ค๋Š” ์ถœ๋ ฅ ๋ฒ„ํผ์— ์ˆœ์„œ๋Œ€๋กœ ๊ธฐ๋กํ•œ๋‹ค

0xf0 ์€ ์Šคํƒ ๋งจ ์œ„๋ฅผ ๊บผ๋‚ด ์ถœ๋ ฅ ๋ฒ„ํผ์— ์ˆœ์„œ๋Œ€๋กœ ๋ถ™์ธ๋‹ค. ๋ฃจํ”„๊ฐ€ ๋๋‚˜๋ฉด ๊ทธ ๋’ค์— 0 ์„ ๋ถ™์—ฌ C ๋ฌธ์ž์—ด๋กœ ๋งˆ๊ฐํ•œ๋‹ค. ๊ทธ๊ฒŒ strcmp ์˜ ์ฒซ ์ธ์ž๊ฐ€ ๋œ๋‹ค.

๋ช…๋ น ์—ฌ๋Ÿ ๊ฐœ, ๋ชจ๋‘ 1๋ฐ”์ดํŠธ ์˜คํผ๋žœ๋“œ ์•„๋‹ˆ๋ฉด ๋ฌด์ธ์ž. ๋ ˆ์ง€์Šคํ„ฐ๋„ ๋ถ„๊ธฐ๋„ ์—†๋‹ค. VM ์ด๋ผ๊ธฐ์—” ์†Œ๋ฐ•ํ•˜์ง€๋งŒ ๋ชฉ์ ์—๋Š” ์ถฉ๋ถ„ํ•˜๋‹ค โ€” ์ •๋‹ต ๋ฌธ์ž์—ด์„ ์•„์Šคํ‚ค๋กœ ์•ˆ ๋ณด์ด๊ฒŒ ๊ฐ์ถ”๋Š” ๊ฒƒ.



๐ŸŽฏ VM ์„ ํŒŒ์ด์ฌ์œผ๋กœ ๊ทธ๋Œ€๋กœ ์˜ฎ๊ธด๋‹ค

์—ญ์‚ฐํ•  ๊ฒŒ ์—†์œผ๋‹ˆ ํ•  ์ผ์€ ํ•˜๋‚˜๋‹ค. .rodata ์—์„œ 247๋ฐ”์ดํŠธ๋ฅผ ๊บผ๋‚ด ์œ„ ํ‘œ๋Œ€๋กœ ์‹คํ–‰ํ•œ๋‹ค.

๋ฐ”์ดํŠธ์ฝ”๋“œ๋ฅผ ๊บผ๋‚ผ ๋•Œ ์˜คํ”„์…‹์„ ์†์œผ๋กœ ๊ณ„์‚ฐํ•ด ํ•˜๋“œ์ฝ”๋”ฉํ•˜์ง€ ์•Š์•˜๋‹ค. ์„น์…˜ ํ—ค๋”๋ฅผ ํ›‘์–ด 0x2020 ์ด ๋“ค์–ด ์žˆ๋Š” ์„น์…˜์„ ์ฐพ๊ณ  ํŒŒ์ผ ์˜คํ”„์…‹์œผ๋กœ ํ™˜์‚ฐํ•œ๋‹ค. ๊ทธ๋ž˜์•ผ ๋‚˜์ค‘์— ์ด ์Šคํฌ๋ฆฝํŠธ๋งŒ ๋ด๋„ ์–ด๋””์„œ ์˜จ ๊ฐ’์ธ์ง€ ์•Œ ์ˆ˜ ์žˆ๋‹ค.

#!/usr/bin/env python3
"""SelfStatus (DreamHack, Bronze 2, reversing) - solver
 
prob ์˜ .rodata 0x2020 ์— ๋ฐ•ํžŒ 247๋ฐ”์ดํŠธ ๋ฐ”์ดํŠธ์ฝ”๋“œ๋ฅผ ๊ทธ๋Œ€๋กœ ๊บผ๋‚ด
0x12e5 ์˜ VM ์„ ํŒŒ์ด์ฌ์œผ๋กœ ์žฌํ˜„ํ•œ๋‹ค. VM ์ถœ๋ ฅ์ด ๊ณง ์ •๋‹ต ํ”Œ๋ž˜๊ทธ๋‹ค
(main ์€ ๊ทธ ์ถœ๋ ฅ๊ณผ ์‚ฌ์šฉ์ž ์ž…๋ ฅ์„ strcmp ๋กœ ๋น„๊ตํ•  ๋ฟ์ด๋‹ค).
"""
import sys
from pathlib import Path
 
ELF = Path(__file__).with_name("extracted") / "prob"
 
CODE_VADDR = 0x2020   # main ์ด vm ์— ๋„˜๊ธฐ๋Š” ์ฒซ ์ธ์ž (lea rax,[rip+0xa11])
CODE_LEN   = 0xF7     # ๋‘ ๋ฒˆ์งธ ์ธ์ž (mov esi,0xf7)
 
# --- .rodata ๋ฅผ ์„น์…˜ ํ—ค๋”๋กœ ์ฐพ์•„ ํŒŒ์ผ ์˜คํ”„์…‹์œผ๋กœ ํ™˜์‚ฐ -------------------
def read_code(path: Path) -> bytes:
    b = path.read_bytes()
    e_shoff  = int.from_bytes(b[0x28:0x30], "little")
    e_shentsize = int.from_bytes(b[0x3A:0x3C], "little")
    e_shnum  = int.from_bytes(b[0x3C:0x3E], "little")
    for i in range(e_shnum):
        sh = b[e_shoff + i * e_shentsize : e_shoff + (i + 1) * e_shentsize]
        addr = int.from_bytes(sh[0x10:0x18], "little")
        off  = int.from_bytes(sh[0x18:0x20], "little")
        size = int.from_bytes(sh[0x20:0x28], "little")
        if addr <= CODE_VADDR < addr + size:          # .rodata ๊ฐ€ ์žกํžŒ๋‹ค
            start = off + (CODE_VADDR - addr)
            return b[start : start + CODE_LEN]
    raise SystemExit("๋ฐ”์ดํŠธ์ฝ”๋“œ๊ฐ€ ๋“  ์„น์…˜์„ ๋ชป ์ฐพ์•˜๋‹ค")
 
# --- 0x12e5 ์˜ VM ์„ ๊ทธ๋Œ€๋กœ ์˜ฎ๊ธด ๊ฒƒ ------------------------------------
PUSH, POP, XOR, ADD, NOP1, NOP2, OUT, HALT = 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xEE, 0xF0, 0xFF
 
def run(code: bytes):
    stack, out, pc = [], bytearray(), 0
    while pc < len(code):
        op = code[pc]; pc += 1
        if op == PUSH:                      # stack[sp++] = code[pc++]
            stack.append(code[pc]); pc += 1
        elif op == POP:                     # if sp: sp--
            if stack: stack.pop()
        elif op == XOR:                     # if sp: stack[-1] ^= code[pc++]
            if not stack: continue
            stack[-1] ^= code[pc]; pc += 1
        elif op == ADD:                     # if sp: stack[-1] += code[pc++]
            if not stack: continue
            stack[-1] = (stack[-1] + code[pc]) & 0xFF; pc += 1
        elif op in (NOP1, NOP2):            # ์˜คํผ๋žœ๋“œ 1๋ฐ”์ดํŠธ๋งŒ ์‚ผํ‚ค๊ณ  ์•„๋ฌด๊ฒƒ๋„ ์•ˆ ํ•œ๋‹ค
            pc += 1
        elif op == OUT:                     # if sp: out[oi++] = stack[--sp]
            if stack: out.append(stack.pop())
        elif op == HALT:
            break
        # ๊ทธ ๋ฐ–์˜ ๋ฐ”์ดํŠธ๋Š” ์˜คํผ๋žœ๋“œ๋ฅผ ์†Œ๋น„ํ•˜์ง€ '์•Š๊ณ ' ๊ทธ๋ƒฅ ๋ฌด์‹œ๋œ๋‹ค
    return bytes(out)
 
# --- ๋ฐ”์ดํŠธ์ฝ”๋“œ ๋””์Šค์–ด์…ˆ๋ธ”๋Ÿฌ (๊ธ€/๊ฒ€์ฆ์šฉ) --------------------------------
def disasm(code: bytes):
    lines, pc = [], 0
    while pc < len(code):
        at, op = pc, code[pc]; pc += 1
        if op in (PUSH, XOR, ADD, NOP1, NOP2):
            arg = code[pc]; pc += 1
            name = {PUSH: "PUSH", XOR: "XOR ", ADD: "ADD ", NOP1: "SKIP", NOP2: "SKIP"}[op]
            lines.append(f"{at:04x}: {op:02x} {arg:02x}   {name} 0x{arg:02x}")
        else:
            name = {POP: "POP", OUT: "OUT", HALT: "HALT"}.get(op, "??? (๋ฌด์‹œ)")
            lines.append(f"{at:04x}: {op:02x}      {name}")
            if op == HALT: break
    return lines
 
if __name__ == "__main__":
    code = read_code(ELF)
    if "-d" in sys.argv:
        lines = disasm(code)
        if "--limit" in sys.argv:
            n = int(sys.argv[sys.argv.index("--limit") + 1])
            lines, rest = lines[:n], len(lines) - n
            if rest > 0:
                lines.append(f"... (๊ฐ™์€ ๋ชจ์–‘์œผ๋กœ {rest}์ค„ ๋”)")
        print("\n".join(lines))
        sys.exit(0)
    flag = run(code)
    print(f"๋ฐ”์ดํŠธ์ฝ”๋“œ {len(code)}๋ฐ”์ดํŠธ -> ์ถœ๋ ฅ {len(flag)}๋ฐ”์ดํŠธ")
    print("FLAG:", flag.decode())

๋Œ๋ฆฌ๊ธฐ ์ „์— ๋จผ์ € ๋””์Šค์–ด์…ˆ๋ธ”๋งŒ ํ•ด ๋ณธ๋‹ค. ์•ž 24์ค„์ด๋ฉด ํŒจํ„ด์ด ๋‹ค ๋ณด์ธ๋‹ค.

python3 solve.py -d --limit 24

solve.py ์˜ ๋ฐ”์ดํŠธ์ฝ”๋“œ ๋””์Šค์–ด์…ˆ๋ธ”๋Ÿฌ ์ถœ๋ ฅ โ€” SKIP ์ด ๋‘์„ธ ๊ฐœ ๋‚˜์˜จ ๋’ค PUSH ์™€ XOR 0x42 ์™€ OUT ์„ธ ๊ฐœ๊ฐ€ ํ•œ ๋ฌถ์Œ์œผ๋กœ ๋ฐ˜๋ณต๋œ๋‹ค
solve.py ์˜ ๋ฐ”์ดํŠธ์ฝ”๋“œ ๋””์Šค์–ด์…ˆ๋ธ”๋Ÿฌ ์ถœ๋ ฅ โ€” SKIP ์ด ๋‘์„ธ ๊ฐœ ๋‚˜์˜จ ๋’ค PUSH ์™€ XOR 0x42 ์™€ OUT ์„ธ ๊ฐœ๊ฐ€ ํ•œ ๋ฌถ์Œ์œผ๋กœ ๋ฐ˜๋ณต๋œ๋‹ค

ํ”„๋กœ๊ทธ๋žจ ์ „์ฒด๊ฐ€ ์ด ํ•œ ๋ฌธ์žฅ์ด๋‹ค.

(SKIP ์—ฌ๋Ÿฌ ๊ฐœ)  PUSH v  XOR 0x42  OUT

๋””์Šค์–ด์…ˆ๋ธ”์€ ์ „์ฒด 137์ค„์ธ๋ฐ, ๊ทธ์ค‘ XOR 26๋ฒˆ์˜ ์ƒ์ˆ˜๊ฐ€ ์ „๋ถ€ 0x42 ํ•˜๋‚˜๋‹ค. ๊ฒฐ๊ตญ ์ถœ๋ ฅ ํ•œ ๊ธ€์ž๋Š” v ^ 0x42 ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด ๋งจ ์•ž PUSH 0x06 ยท XOR 0x42 ๋Š” 0x44 = 'D' ๋ฅผ ๋‚ธ๋‹ค.

0xa2(POP)์™€ 0xa4(ADD)๋Š” ํ•ธ๋“ค๋Ÿฌ๊ฐ€ ์žˆ๋Š”๋ฐ ํ•œ ๋ฒˆ๋„ ์‹คํ–‰๋˜์ง€ ์•Š๋Š”๋‹ค. 247๋ฐ”์ดํŠธ ์•ˆ์—์„œ 0xa2 ๋Š” ๋”ฑ ํ•œ ๋ฒˆ ๋‚˜์˜ค๋Š”๋ฐ ๊ทธ๋งˆ์ € SKIP ์˜ ์˜คํผ๋žœ๋“œ ์ž๋ฆฌ๊ณ , 0xa4 ๋Š” ์•„์˜ˆ ํ•œ ๋ฒˆ๋„ ์•ˆ ๋‚˜์˜จ๋‹ค. ์ธํ„ฐํ”„๋ฆฌํ„ฐ๋ฅผ ์ฝ๋Š” ์‚ฌ๋žŒ ํ—ท๊ฐˆ๋ฆฌ๋ผ๊ณ  ๋„ฃ์–ด ๋‘” ๋ช…๋ น๋“ค์ด๋‹ค.

๊ทธ๋ž˜์„œ ์‹คํ–‰ ๊ฒฐ๊ณผ๋„ ์˜ˆ์ƒ๋Œ€๋กœ๋‹ค.

python3 solve.py

solve.py ์‹คํ–‰ ๊ฒฐ๊ณผ โ€” ๋ฐ”์ดํŠธ์ฝ”๋“œ 247๋ฐ”์ดํŠธ์—์„œ 26๋ฐ”์ดํŠธ๋ฅผ ๋ฝ‘์•„ DH ๋กœ ์‹œ์ž‘ํ•˜๋Š” ํ”Œ๋ž˜๊ทธ๋ฅผ ๊ทธ๋Œ€๋กœ ์ถœ๋ ฅํ•œ๋‹ค
solve.py ์‹คํ–‰ ๊ฒฐ๊ณผ โ€” ๋ฐ”์ดํŠธ์ฝ”๋“œ 247๋ฐ”์ดํŠธ์—์„œ 26๋ฐ”์ดํŠธ๋ฅผ ๋ฝ‘์•„ DH ๋กœ ์‹œ์ž‘ํ•˜๋Š” ํ”Œ๋ž˜๊ทธ๋ฅผ ๊ทธ๋Œ€๋กœ ์ถœ๋ ฅํ•œ๋‹ค

DH{S3lfSt4tus_VM_By7ec0d3}. 26๊ธ€์ž.


๐Ÿ› ์กฐ์šฉํžˆ ํ‹€๋ฆฌ๋Š” ์ง€์ 

์ด VM ์—์„œ ์–ด๊ธ‹๋‚  ์ˆ˜ ์žˆ๋Š” ์ž๋ฆฌ๋Š” ์‚ฌ์‹ค์ƒ ํ•˜๋‚˜๋ฟ์ธ๋ฐ, ๊ทธ ํ•˜๋‚˜๊ฐ€ ํ‹ฐ๊ฐ€ ์ž˜ ์•ˆ ๋‚œ๋‹ค. ์ง์ž‘์œผ๋กœ ๋„˜๊ธฐ์ง€ ์•Š์œผ๋ ค๊ณ  ํ‹€๋ฆฐ ํ•ด์„์„ ์‹ค์ œ๋กœ ๋Œ๋ ค ๋ดค๋‹ค.

โ–ถ๐Ÿ› ํ•จ์ • โ€” 0xee ๋ฅผ ๊ทธ๋ƒฅ NOP ์œผ๋กœ ์ฝ์œผ๋ฉด 'DH' ๊นŒ์ง€๋งŒ ๋‚˜์˜จ๋‹ค

0xa5 ยท 0xee ํ•ธ๋“ค๋Ÿฌ๋Š” add QWORD PTR [rbp-0x98],0x1 ํ•œ ์ค„์ด ์ „๋ถ€๋‹ค. ์—ฌ๊ธฐ์„œ rbp-0x98 ์€ pc ๋‹ค.

fetch ๋‹จ๊ณ„์—์„œ ์ด๋ฏธ pc++ ๋ฅผ ํ•œ ๋’ค์ด๋ฏ€๋กœ ์ด ํ•œ ์ค„์€ ๋‹ค์Œ 1๋ฐ”์ดํŠธ๋ฅผ ์˜คํผ๋žœ๋“œ๋กœ ์‚ผ์ผœ ๋ฒ„๋ฆฐ๋‹ค๋Š” ๋œป์ด๋‹ค. ๊ทธ๋Ÿฐ๋ฐ ํ•ธ๋“ค๋Ÿฌ ๋ณธ๋ฌธ๋งŒ ๋–ผ์–ด ๋†“๊ณ  ๋ณด๋ฉด "pc ๋ฅผ 1 ์ฆ๊ฐ€์‹œํ‚จ๋‹ค = ๊ทธ๋ƒฅ ๋‹ค์Œ ๋ช…๋ น์œผ๋กœ ๊ฐ„๋‹ค = NOP" ์œผ๋กœ ์ฝ๊ธฐ ๋”ฑ ์ข‹๋‹ค. ๊ทธ๋Ÿฌ๋ฉด ์˜คํผ๋žœ๋“œ ์ž๋ฆฌ ๋ฐ”์ดํŠธ๊ฐ€ ์ „๋ถ€ opcode ๋กœ ์žฌํ•ด์„๋˜๋ฉด์„œ ์ŠคํŠธ๋ฆผ์ด ํ†ต์งธ๋กœ ์–ด๊ธ‹๋‚œ๋‹ค.

์‹ค์ œ๋กœ ์–ด๋–ป๊ฒŒ ๋˜๋Š”์ง€ ์žฌ ๋ดค๋‹ค.

#!/usr/bin/env python3
"""SelfStatus โ€” ๋ฐ”์ดํŠธ์ฝ”๋“œ๋ฅผ ์ž˜๋ชป ์ฝ์œผ๋ฉด ์–ด๋–ป๊ฒŒ ๋˜๋Š”์ง€ ์‹ค์ธกํ•˜๋Š” ์Šคํฌ๋ฆฝํŠธ.
 
์„ธ ๊ฐ€์ง€๋ฅผ ์žฌ ๋ณธ๋‹ค.
  [A] 0xee ๋ฅผ '์˜คํผ๋žœ๋“œ ์—†๋Š” NOP' ์œผ๋กœ ์ฝ์—ˆ์„ ๋•Œ (pc += 0)
  [B] 0xa5 / 0xee ๋ฅผ ์•„์˜ˆ '์•Œ ์ˆ˜ ์—†๋Š” opcode' ๋กœ ๋ฌด์‹œํ–ˆ์„ ๋•Œ
  [C] ์˜ฌ๋ฐ”๋ฅธ ํ•ด์„ (๋‘˜ ๋‹ค ์˜คํผ๋žœ๋“œ 1๋ฐ”์ดํŠธ๋ฅผ ์‚ผํ‚จ๋‹ค)
๊ทธ๋ฆฌ๊ณ  ๊ฐ ๊ฒฐ๊ณผ๋ฅผ ๋ฌธ์ œ ๋ฐ”์ด๋„ˆ๋ฆฌ์— ๊ทธ๋Œ€๋กœ ๋„ฃ์–ด ํŒ์ •์„ ๋ฐ›์•„ ์˜จ๋‹ค.
"""
import subprocess
from solve import read_code, ELF
 
code = read_code(ELF)
 
def run(code, ee_skips=1, a5_skips=1):
    stack, out, pc = [], bytearray(), 0
    stats = {"unknown": 0, "ops": 0, "junk_bytes": 0}
    while pc < len(code):
        op = code[pc]; pc += 1; stats["ops"] += 1
        if op == 0xA1:
            stack.append(code[pc]); pc += 1
        elif op == 0xA2:
            if stack: stack.pop()
        elif op == 0xA3:
            if stack: stack[-1] ^= code[pc]; pc += 1
        elif op == 0xA4:
            if stack: stack[-1] = (stack[-1] + code[pc]) & 0xFF; pc += 1
        elif op == 0xA5:
            pc += a5_skips; stats["junk_bytes"] += 1 + a5_skips
        elif op == 0xEE:
            pc += ee_skips; stats["junk_bytes"] += 1 + ee_skips
        elif op == 0xF0:
            if stack: out.append(stack.pop())
        elif op == 0xFF:
            break
        else:
            stats["unknown"] += 1
    return bytes(out), stats
 
def ask_binary(candidate: bytes) -> str:
    p = subprocess.run([str(ELF)], input=candidate + b"\n",
                       capture_output=True)
    return p.stdout.decode(errors="replace").replace("Enter flag: ", "").strip()
 
for label, kw in (("[A] 0xee ๋ฅผ pc+=0 NOP ์œผ๋กœ", dict(ee_skips=0)),
                  ("[B] 0xa5/0xee ๋ฅผ ๋ฏธ์ง€ opcode ๋กœ", dict(ee_skips=0, a5_skips=0)),
                  ("[C] ์˜ฌ๋ฐ”๋ฅธ ํ•ด์„ (pc+=1)",        dict())):
    out, st = run(code, **kw)
    shown = out.decode("latin-1").encode("unicode_escape").decode()
    print(f"{label}: {len(out)}๋ฐ”์ดํŠธ")
    print(f"     out  = {shown[:120]}")
    print(f"     ํŒ์ • = {ask_binary(out)}   (๋ฏธ์ง€ opcode {st['unknown']}ํšŒ)")
 
out, st = run(code)
print()
print(f"๋ฐ”์ดํŠธ์ฝ”๋“œ ์ด {len(code)}๋ฐ”์ดํŠธ ์ค‘ SKIP(0xa5/0xee)์ด ๋จน์€ ์ž‰์—ฌ = {st['junk_bytes']}๋ฐ”์ดํŠธ")
print(f"์‹ค์ œ๋กœ ์ถœ๋ ฅ์— ๊ธฐ์—ฌํ•œ ๋ฐ”์ดํŠธ = {len(code) - st['junk_bytes']}๋ฐ”์ดํŠธ")
python3 traps.py

traps.py ์‹คํ–‰ ๊ฒฐ๊ณผ โ€” ์ž˜๋ชป ์ฝ์€ ๋‘ ํ•ด์„์€ DH ๋‘ ๊ธ€์ž๋งŒ ๋ฝ‘๊ณ  ๋ฌธ์ œ ๋ฐ”์ด๋„ˆ๋ฆฌ๊ฐ€ Wrong ์„ ๋Œ๋ ค์ฃผ๋ฉฐ ์˜ฌ๋ฐ”๋ฅธ ํ•ด์„๋งŒ 26๋ฐ”์ดํŠธ์™€ Correct ๋ฅผ ๋ฐ›๋Š”๋‹ค
traps.py ์‹คํ–‰ ๊ฒฐ๊ณผ โ€” ์ž˜๋ชป ์ฝ์€ ๋‘ ํ•ด์„์€ DH ๋‘ ๊ธ€์ž๋งŒ ๋ฝ‘๊ณ  ๋ฌธ์ œ ๋ฐ”์ด๋„ˆ๋ฆฌ๊ฐ€ Wrong ์„ ๋Œ๋ ค์ฃผ๋ฉฐ ์˜ฌ๋ฐ”๋ฅธ ํ•ด์„๋งŒ 26๋ฐ”์ดํŠธ์™€ Correct ๋ฅผ ๋ฐ›๋Š”๋‹ค

DH ๋‹ค. ํ”Œ๋ž˜๊ทธ ์ ‘๋‘์‚ฌ๊ฐ€ ์ •ํ™•ํžˆ ๋‚˜์˜จ๋‹ค.

์ด๊ฒŒ ๊ณ ์•ฝํ•œ ์ด์œ ๊ฐ€ ์—ฌ๊ธฐ ์žˆ๋‹ค. ์–ด๊ธ‹๋‚œ ํ•ด์„์ด ์ฒ˜์Œ ๋‘ ๊ธ€์ž๋ฅผ ๋งžํžˆ๊ณ  ๋‚˜์„œ ๋ฉˆ์ถ”๋‹ˆ๊นŒ, "ํฌ๋งท์€ ๋งž๋Š”๋ฐ ๋’ค๊ฐ€ ์™œ ์•ˆ ๋‚˜์˜ค์ง€" ์ชฝ์œผ๋กœ ์ƒ๊ฐ์ด ํ˜๋Ÿฌ๊ฐ„๋‹ค. ์ธ์ฝ”๋”ฉ์„ ์˜์‹ฌํ•˜๊ฑฐ๋‚˜ ๊ธธ์ด ํ•„๋“œ๋ฅผ ์ฐพ๊ฒŒ ๋˜์ง€, ์ •์ž‘ pc ๊ณ„์‚ฐ์„ ๋‹ค์‹œ ๋ณด๊ฒŒ ๋˜์ง€๋Š” ์•Š๋Š”๋‹ค.

๋ฉˆ์ถ˜ ์œ„์น˜๋„ ์šฐ์—ฐ์ด ์•„๋‹ˆ๋‹ค. ์˜คํ”„์…‹ 0x0018 ์˜ ๋ฐ”์ดํŠธ ์Œ์€ ee ff ์ธ๋ฐ, ์–ด๊ธ‹๋‚œ ํ•ด์„์—์„œ๋Š” ์ด 0xff ๊ฐ€ ์˜คํผ๋žœ๋“œ๊ฐ€ ์•„๋‹ˆ๋ผ HALT opcode ๋กœ ์ฝํžŒ๋‹ค. ๋‚œ๋…ํ™”์šฉ ์“ฐ๋ ˆ๊ธฐ ๋ฐ”์ดํŠธ ์‚ฌ์ด์— 0xff ๊ฐ€ ์„ž์—ฌ ์žˆ์–ด์„œ, ์ŠคํŠธ๋ฆผ์ด ๋ฐ€๋ฆฌ๋Š” ์ˆœ๊ฐ„ ์กฐ๊ธฐ ์ข…๋ฃŒ๊ฐ€ ๊ฑธ๋ฆฌ๋Š” ๊ตฌ์กฐ๋‹ค. ์‹ค์ œ๋กœ 0xff ๋Š” 247๋ฐ”์ดํŠธ ์•ˆ์— ์„ธ ๋ฒˆ ๋‚˜์˜ค๋Š”๋ฐ opcode ์ž๋ฆฌ์ธ ๊ฑด ๋งจ ๋ ํ•˜๋‚˜๋ฟ์ด๋‹ค. ๋‚˜๋จธ์ง€ ๋‘˜์€ ์˜คํผ๋žœ๋“œ๋กœ ์ˆจ์–ด ์žˆ๋‹ค๊ฐ€ ํ•ด์„์ด ์–ด๊ธ‹๋‚  ๋•Œ๋งŒ ๊นจ์–ด๋‚œ๋‹ค.

์ˆซ์ž๋กœ๋„ ํ™•์ธ๋œ๋‹ค. 247๋ฐ”์ดํŠธ ์ค‘ SKIP ์ด ๋จน์–ด์น˜์šฐ๋Š” ๊ฒŒ 116๋ฐ”์ดํŠธ๋กœ ์ „์ฒด์˜ 47%๋‹ค. ์ง„์งœ ์ผํ•˜๋Š” ๊ฑด 131๋ฐ”์ดํŠธ๋ฟ์ด๊ณ , ๊ทธ ์•ˆ์—์„œ PUSH ยท XOR ยท OUT ์ด 26์„ธํŠธ๋ฅผ ์ด๋ฃฌ๋‹ค.

๊ทธ๋ฆฌ๊ณ  ํŒ์ •์„ ๋ˆˆ์œผ๋กœ ํ•˜์ง€ ์•Š์•˜๋‹ค๋Š” ์ ์ด ์ค‘์š”ํ•˜๋‹ค. ์„ธ ํ•ด์„์˜ ๊ฒฐ๊ณผ๋ฅผ ์ „๋ถ€ ๋ฌธ์ œ ๋ฐ”์ด๋„ˆ๋ฆฌ์— ๊ทธ๋Œ€๋กœ ๋จน์—ฌ Wrong! / Correct! ๋ฅผ ๋ฐ›์•„ ์™”๋‹ค. ํ›„๋ณด๊ฐ€ ๊ทธ๋Ÿด๋“ฏํ•ด ๋ณด์ด๋Š”์ง€๋Š” ํŒ๋‹จ ๊ทผ๊ฑฐ๊ฐ€ ๋ชป ๋œ๋‹ค.



๐Ÿ”“ ๋Ÿฐํƒ€์ž„์œผ๋กœ ๋ชป๋ฐ•๊ธฐ โ€” anti-debug ๋งŒ ๊บผ ๋ณธ๋‹ค

์—ฌ๊ธฐ๊นŒ์ง€๋Š” ์ „๋ถ€ ์ •์  ๋ถ„์„์ด๋‹ค. strcmp ์˜ ์ฒซ ์ธ์ž๊ฐ€ ์ •๋ง ์ € ๋ฌธ์ž์—ด์ธ์ง€ ์‹คํ–‰ ์ค‘์— ์ง์ ‘ ๋ณด๊ณ  ์‹ถ์€๋ฐ, ๋””๋ฒ„๊ฑฐ๋ฅผ ๋ถ™์ด๋ฉด ํ”„๋กœ๊ทธ๋žจ์ด ์ฃฝ๋Š”๋‹ค.

์•ž์—์„œ ๋ณธ ๋Œ€๋กœ ๊ฒ€์‚ฌ๋Š” open("/proc/self/status") ํ•œ ์ค„์— ์˜์กดํ•˜๊ณ , prob ์€ ๊ทธ open ์„ PLT ๋กœ ๋ถ€๋ฅธ๋‹ค. ๊ทธ๋Ÿฌ๋ฉด LD_PRELOAD ๋กœ open ๋งŒ ๊ฐ€๋กœ์ฑ„๋ฉด ๋œ๋‹ค. ๋‹ค๋ฅธ ๊ฑด ์•„๋ฌด๊ฒƒ๋„ ์•ˆ ๊ฑด๋“œ๋ฆฐ๋‹ค.

/* nostatus.c โ€” prob ์˜ anti-debug ๋ฅผ ๋ฌด๋ ฅํ™”ํ•˜๋Š” LD_PRELOAD ์‹ฌ.
 *
 * prob ์€ open("/proc/self/status") ๋กœ ์ž๊ธฐ ์ƒํƒœ๋ฅผ ์ฝ์–ด TracerPid ๋ฅผ ๋ณธ๋‹ค.
 * ๊ทธ open ํ˜ธ์ถœ๋งŒ ๊ฐ€๋กœ์ฑ„ ์šฐ๋ฆฌ๊ฐ€ ๋งŒ๋“  fake_status ๋กœ ๋Œ๋ฆฐ๋‹ค.
 *   gcc -shared -fPIC -o nostatus.so nostatus.c -ldl
 */
#define _GNU_SOURCE
#include <dlfcn.h>
#include <fcntl.h>
#include <stdarg.h>
#include <string.h>
#include <sys/types.h>
 
int open(const char *path, int flags, ...)
{
    static int (*real_open)(const char *, int, ...);
    if (!real_open)
        real_open = dlsym(RTLD_NEXT, "open");
 
    mode_t mode = 0;
    if (flags & O_CREAT) {
        va_list ap;
        va_start(ap, flags);
        mode = va_arg(ap, int);
        va_end(ap);
    }
 
    if (strcmp(path, "/proc/self/status") == 0)
        path = "./fake_status";
 
    return real_open(path, flags, mode);
}
gcc -shared -fPIC -o nostatus.so nostatus.c -ldl
printf 'Name:\tprob\nState:\tR (running)\nTracerPid:\t0\nUid:\t1000\t1000\t1000\t1000\n' > fake_status
printf 'AAAA\n' > input.txt

์ด์ œ gdb ๋กœ strcmp ํ˜ธ์ถœ ์ง์ „์— ๋ฉˆ์ถฐ ์ธ์ž ๋‘˜์„ ๊ทธ๋Œ€๋กœ ์ฝ๋Š”๋‹ค. PIE ๋ผ์„œ ๋กœ๋“œ ์ฃผ์†Œ๋ฅผ ๊ด€๋ก€๋กœ ๊ฐ€์ •ํ•˜์ง€ ์•Š๊ณ  info proc mappings ์—์„œ ์‹ค์ œ ๊ฐ’์„ ๋ฐ›์•„ ์™”๋‹ค.

# dump_expected.gdb โ€” VM ์ด ๋งŒ๋“ค์–ด ๋‚ธ "์ •๋‹ต ๋ฌธ์ž์—ด"์„ ์‹คํ–‰ ์ค‘์— ์ง์ ‘ ๊บผ๋‚ด ๋ณธ๋‹ค.
#   LD_PRELOAD ์‹ฌ์œผ๋กœ anti-debug ๋ฅผ ๋ˆ ๋’ค strcmp ํ˜ธ์ถœ ์ง์ „(ํŒŒ์ผ ์˜คํ”„์…‹ 0x162b)์— ๋ฉˆ์ถ”๊ณ 
#   rdi(= VM ์ถœ๋ ฅ ๋ฒ„ํผ) ์™€ rsi(= ์‚ฌ์šฉ์ž ์ž…๋ ฅ) ๋ฅผ ๊ทธ๋Œ€๋กœ ์ฝ๋Š”๋‹ค.
set confirm off
set pagination off
set environment LD_PRELOAD ./nostatus.so
starti < input.txt
python
import gdb
base = None
for line in gdb.execute("info proc mappings", to_string=True).splitlines():
    parts = line.split()
    if parts and parts[-1].endswith("/prob"):
        base = int(parts[0], 16)
        break
print("PIE base = %#x  (info proc mappings ๋กœ ํ™•์ธ, ๊ด€๋ก€ ๊ฐ€์ • ๊ธˆ์ง€)" % base)
gdb.execute("break *%#x" % (base + 0x162b))
gdb.execute("continue")
gdb.execute('printf "rdi (VM ์ด ์กฐ๋ฆฝํ•œ ์ •๋‹ต) = %s\\n", (char*)$rdi')
gdb.execute('printf "rsi (๋‚ด๊ฐ€ ๋„ฃ์€ ์ž…๋ ฅ)    = %s\\n", (char*)$rsi')
end
kill
gdb -q -batch -x dump_expected.gdb --args ./extracted/prob

gdb ๋Ÿฐํƒ€์ž„ ๊ฒ€์ฆ โ€” LD_PRELOAD ์‹ฌ์œผ๋กœ anti-debug ๋ฅผ ๋ˆ ๋’ค strcmp ์ง์ „์— ๋ฉˆ์ถฐ rdi ์—๋Š” VM ์ด ๋งŒ๋“  26๊ธ€์ž ์ •๋‹ต์ด rsi ์—๋Š” ๋‚ด๊ฐ€ ๋„ฃ์€ AAAA ๊ฐ€ ๋“ค์–ด ์žˆ์Œ์„ ํ™•์ธํ–ˆ๋‹ค
gdb ๋Ÿฐํƒ€์ž„ ๊ฒ€์ฆ โ€” LD_PRELOAD ์‹ฌ์œผ๋กœ anti-debug ๋ฅผ ๋ˆ ๋’ค strcmp ์ง์ „์— ๋ฉˆ์ถฐ rdi ์—๋Š” VM ์ด ๋งŒ๋“  26๊ธ€์ž ์ •๋‹ต์ด rsi ์—๋Š” ๋‚ด๊ฐ€ ๋„ฃ์€ AAAA ๊ฐ€ ๋“ค์–ด ์žˆ์Œ์„ ํ™•์ธํ–ˆ๋‹ค

Enter flag: ํ”„๋กฌํ”„ํŠธ๊ฐ€ ์ •์ƒ์ ์œผ๋กœ ๋œฌ๋‹ค. anti-debug ๊ฐ€ ๊บผ์ง„ ๊ฒƒ์ด๋‹ค.

๊ทธ๋ฆฌ๊ณ  ๋ธŒ๋ ˆ์ดํฌํฌ์ธํŠธ์—์„œ rdi ๋Š” DH{S3lfSt4tus_VM_By7ec0d3}, rsi ๋Š” ๋‚ด๊ฐ€ ๋„ฃ์€ AAAA ๋‹ค. ์ •์  ๋ถ„์„์ด ๋งํ•œ ๊ฒƒ โ€” "VM ์ถœ๋ ฅ์ด ๊ณง ์ •๋‹ต์ด๊ณ  ์ž…๋ ฅ์€ ๋งˆ์ง€๋ง‰ ๋น„๊ต์—์„œ๋งŒ ์“ฐ์ธ๋‹ค" โ€” ์ด ์‹คํ–‰ ์ค‘์—๋„ ๊ทธ๋Œ€๋กœ๋‹ค.

printf ์•ˆ์˜ ํ•œ๊ธ€ ๋ผ๋ฒจ์€ ๋‚ด๊ฐ€ dump_expected.gdb ์— ์ ์–ด ๋„ฃ์€ ๊ฒƒ์ด์ง€ gdb ๊ฐ€ ์›๋ž˜ ์ฐ์–ด ์ฃผ๋Š” ๋ฌธ๊ตฌ๊ฐ€ ์•„๋‹ˆ๋‹ค.


๐Ÿš€ ์žฌํ˜„

ํ”Œ๋ž˜๊ทธ๊ฐ€ ๋งž๋Š”์ง€๋Š” ๋ˆˆ์œผ๋กœ ๋Œ€์กฐํ•˜์ง€ ์•Š๊ณ  ๋ฌธ์ œ ๋ฐ”์ด๋„ˆ๋ฆฌ์—๊ฒŒ ์ง์ ‘ ๋ฌผ์—ˆ๋‹ค.

#!/usr/bin/env python3
"""solve.py ๊ฐ€ ๋ฝ‘์€ ๊ฐ’์„ ๋ฌธ์ œ ๋ฐ”์ด๋„ˆ๋ฆฌ์— ๊ทธ๋Œ€๋กœ ๋จน์—ฌ ํŒ์ •์„ ๋ฐ›์•„ ์˜จ๋‹ค."""
import subprocess
from solve import read_code, ELF, run
 
flag = run(read_code(ELF)).decode()
p = subprocess.run([str(ELF)], input=flag + "\n", capture_output=True, text=True)
print(f"์ž…๋ ฅ : {flag}")
print(f"์ถœ๋ ฅ : {p.stdout.replace(chr(0), '').strip()}")
print(f"ํŒ์ • : {'PASS' if 'Correct' in p.stdout else 'FAIL'}")
python3 verify.py

verify.py ์‹คํ–‰ ๊ฒฐ๊ณผ โ€” solve.py ๊ฐ€ ๋งŒ๋“  26๊ธ€์ž๋ฅผ ๋ฌธ์ œ ๋ฐ”์ด๋„ˆ๋ฆฌ์— ๋„ฃ์–ด Correct ์ถœ๋ ฅ๊ณผ PASS ํŒ์ •์„ ๋ฐ›์•˜๋‹ค
verify.py ์‹คํ–‰ ๊ฒฐ๊ณผ โ€” solve.py ๊ฐ€ ๋งŒ๋“  26๊ธ€์ž๋ฅผ ๋ฌธ์ œ ๋ฐ”์ด๋„ˆ๋ฆฌ์— ๋„ฃ์–ด Correct ์ถœ๋ ฅ๊ณผ PASS ํŒ์ •์„ ๋ฐ›์•˜๋‹ค

Correct!.

๋ฌธ์ œ ํด๋”์—๋Š” ์ด๊ฑธ ํ•œ ๋ฒˆ์— ๋„๋Š” reproduce.sh ๋ฅผ ๊ฐ™์ด ๋‚จ๊ฒจ ๋’€๋‹ค. ๋‚˜์ค‘์— ๋ฐฑ์—…๋งŒ ๊บผ๋‚ด๋„ ๋ฐ”๋กœ ๋Œ์•„๊ฐ„๋‹ค.

#!/usr/bin/env bash
# SelfStatus (DreamHack #1983, Bronze 2, reversing) โ€” ํ•œ ๋ฐฉ ์žฌํ˜„.
#   .rodata ์˜ VM ๋ฐ”์ดํŠธ์ฝ”๋“œ๋ฅผ ํŒŒ์ด์ฌ์œผ๋กœ ๋Œ๋ ค flag ๋ฅผ ๋งŒ๋“ค๊ณ ,
#   ๊ทธ ๊ฐ’์„ ๋ฌธ์ œ ๋ฐ”์ด๋„ˆ๋ฆฌ์— ๋„ฃ์–ด Correct! ๊ฐ€ ๋‚˜์˜ค๋Š”์ง€๊นŒ์ง€ ํ™•์ธํ•œ๋‹ค.
set -eu
cd "$(dirname "$(readlink -f "$0")")"
 
EXPECT=$(python3 -c "import json;print(json.load(open('๋ฌธ์ œ.json'))['flag'])" 2>/dev/null || echo '')
 
chmod +x extracted/prob
OUT=$(timeout 60 python3 verify.py 2>&1) || true
echo "$OUT"
 
FLAG=$(printf '%s' "$OUT" | grep -aoE 'DH\{[^}]+\}' | head -1)
if [ -n "$FLAG" ] && printf '%s' "$OUT" | grep -q 'PASS' \
   && { [ -z "$EXPECT" ] || [ "$FLAG" = "$EXPECT" ]; }; then
  echo; echo "โœ… PASS  $FLAG"; exit 0
fi
echo; echo "โŒ FAIL (์–ป์€ ๊ฐ’: '${FLAG:-์—†์Œ}' / ๊ธฐ๋Œ€: '$EXPECT')"; exit 1

๋Œ๋ฆฐ ํ™˜๊ฒฝ์€ Ubuntu 25.10 ยท glibc 2.42 ยท gcc 15.2.0 ยท gdb 16.3 ยท binutils 2.45 ยท Python 3.13.7 ์ด๋‹ค.

prob ์€ libc ๋ง๊ณ ๋Š” ์•„๋ฌด๊ฒƒ๋„ ์•ˆ ์“ฐ๊ณ  ๋ฐฐํฌ๋ณธ ๊ทธ๋Œ€๋กœ ์‹คํ–‰๋˜๋ฏ€๋กœ libc ๋ฒ„์ „์„ ๋งž์ถœ ํ•„์š”๊ฐ€ ์—†๋‹ค. ์ฐธ๊ณ ๋กœ ๋ฐฐํฌ๋ณธ์˜ .comment ์—๋Š” GCC 14.2.1 20250207 ์ด ๋ฐ•ํ˜€ ์žˆ๋Š”๋ฐ, ๊ทธ๊ฑด ์ถœ์ œ์ž๊ฐ€ ๋นŒ๋“œํ•œ ์ปดํŒŒ์ผ๋Ÿฌ์ด์ง€ ์ด ๊ธ€์„ ์“ฐ๋ฉฐ ์“ด ๊ฒƒ์ด ์•„๋‹ˆ๋‹ค. nostatus.so ๋งŒ ์œ„ gcc ๋กœ ์ƒˆ๋กœ ๋นŒ๋“œํ–ˆ๋‹ค.



๐Ÿ“ ๊ฒฐ๋ก 

anti-debug ๋Š” ๋ฐฉ์–ด๊ฐ€ ์•„๋‹ˆ๋ผ ํ‘œ์ง€ํŒ์ด์—ˆ๋‹ค.

/proc/self/status ๋ฅผ ์ฝ๋Š” ๊ฒ€์‚ฌ๋Š” ์šฐํšŒ๊ฐ€ ์‰ฝ๋‹ค. ํŒŒ์ผ์„ ๋ชป ์—ด๋ฉด ํ†ต๊ณผ, ๋ชป ์ฝ์–ด๋„ ํ†ต๊ณผ, ๊ทธ ์ค„์ด ์—†์–ด๋„ ํ†ต๊ณผ โ€” ์‹คํŒจ๊ฐ€ ์ „๋ถ€ ์•ˆ์ „ํ•œ ์ชฝ์œผ๋กœ ๋–จ์–ด์ง„๋‹ค. open ํ•˜๋‚˜๋งŒ ๊ฐ€๋กœ์ฑ„๋ฉด ๋๋‚œ๋‹ค.

์˜คํžˆ๋ ค ์ด ๊ฒ€์‚ฌ์˜ ์กด์žฌ ์ž์ฒด๊ฐ€ "์—ฌ๊ธฐ ๋ญ”๊ฐ€ ์ˆจ๊ฒจ์ ธ ์žˆ๋‹ค"๋Š” ์‹ ํ˜ธ์˜€๋‹ค. ํ”„๋กœ๊ทธ๋žจ์ด ์ž๊ธฐ ์ƒํƒœ๋ฅผ ํ™•์ธํ•˜๋Š” ์ฝ”๋“œ๋ฅผ ๋„ฃ์—ˆ๋‹ค๋Š” ๊ฑด ์‹คํ–‰ ์ค‘ ๊ด€์ฐฐ์„ ๋ง‰๊ณ  ์‹ถ๋‹ค๋Š” ๋œป์ด๊ณ , ๋ง‰๊ณ  ์‹ถ์€ ๊ฒŒ ๋ญ”์ง€๋Š” ๊ทธ ๋’ค์— ์žˆ๋‹ค.

์ง„์งœ ๋ฐฉ์–ด๋Š” VM ์ชฝ์ด์—ˆ๋‹ค.

.rodata ์— ๋ฌธ์ž์—ด์„ ๊ทธ๋ƒฅ ๋‘๋ฉด strings ํ•œ ์ค„์— ๋๋‚œ๋‹ค. ๋ฐ”์ดํŠธ์ฝ”๋“œ๋กœ ์ ‘์–ด ๋‘๋ฉด ์ตœ์†Œํ•œ ์ธํ„ฐํ”„๋ฆฌํ„ฐ๋ฅผ ์ฝ์–ด์•ผ ํ•œ๋‹ค. ์—ฌ๊ธฐ์— ์•„๋ฌด ์ผ๋„ ์•ˆ ํ•˜๋ฉด์„œ ๋‹ค์Œ ๋ฐ”์ดํŠธ๋ฅผ ์‚ผํ‚ค๋Š” ๋ช…๋ น์„ ์ ˆ๋ฐ˜์ฏค ์„ž์–ด ๋‘๋‹ˆ, ๋ˆˆ์œผ๋กœ ํ›‘์„ ๋•Œ๋Š” ๊ทœ์น™์ด ์•ˆ ๋ณด์ธ๋‹ค.

๊ทธ๋ž˜๋„ ํ•œ๊ณ„๋Š” ๋ถ„๋ช…ํ•˜๋‹ค. ์ •๋‹ต์ด ์‹คํ–‰ ์ค‘ ์–ด๋”˜๊ฐ€์—๋Š” ๋ฐ˜๋“œ์‹œ ํ‰๋ฌธ์œผ๋กœ ์กด์žฌํ•˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. strcmp ๋ฅผ ์“ฐ๋Š” ์ด์ƒ ๋น„๊ต ์ง์ „์— ์™„์„ฑ๋œ ๋ฌธ์ž์—ด์ด ๋ฉ”๋ชจ๋ฆฌ์— ๋†“์ธ๋‹ค. ๋ธŒ๋ ˆ์ดํฌํฌ์ธํŠธ ํ•˜๋‚˜๋ฉด ๋๋‚œ๋‹ค.

์—ฐ์‚ฐ ๊ฒฐ๊ณผ๊ฐ€ ์•„๋‹ˆ๋ผ ํ๋ฆ„์„ ๋จผ์ € ๋ณธ๋‹ค.

์ด ๋ฌธ์ œ์—์„œ ์‹œ๊ฐ„์„ ์•„๋‚€ ํŒ๋‹จ์€ "์ž…๋ ฅ์ด ์–ด๋А ์ง€์ ์—์„œ ์ฒ˜์Œ ์“ฐ์ด๋Š”๊ฐ€"๋ฅผ ๋จผ์ € ํ™•์ธํ•œ ๊ฒƒ์ด๋‹ค. vm(code, len, out) ์˜ ์ธ์ž ์…‹์— ์ž…๋ ฅ์ด ์—†๋‹ค๋Š” ๊ฑธ ๋ณด๋Š” ์ˆœ๊ฐ„ ์—ญ์‚ฐ์ด ํ•„์š” ์—†๋‹ค๋Š” ๊ฒŒ ์ •ํ•ด์กŒ๋‹ค. ํฌ๋ž™๋ฏธ๋ผ๊ณ  ํ•ด์„œ ํ•ญ์ƒ ์ž…๋ ฅ์„ ๋ณ€ํ™˜ํ•ด ๋น„๊ตํ•˜๋Š” ๊ฑด ์•„๋‹ˆ๋‹ค.

๋ง‰ํž ๋• ํŒ์ •์„ ๋ฐ”์ด๋„ˆ๋ฆฌ์—๊ฒŒ ๋„˜๊ธด๋‹ค.

0xee ๋ฅผ ์ž˜๋ชป ์ฝ์€ ํ•ด์„์€ DH ๋ผ๋Š” ๊ทธ๋Ÿด๋“ฏํ•œ ๋‘ ๊ธ€์ž๋ฅผ ๋ฑ‰๋Š”๋‹ค. ์‚ฌ๋žŒ ๋ˆˆ์œผ๋กœ๋Š” "๊ฑฐ์˜ ๋‹ค ์™”๋‹ค"๋กœ ๋ณด์ธ๋‹ค. ํ›„๋ณด๊ฐ€ ๋‚˜์˜ฌ ๋•Œ๋งˆ๋‹ค ๋ฌธ์ œ ๋ฐ”์ด๋„ˆ๋ฆฌ์— ๊ทธ๋Œ€๋กœ ๋จน์—ฌ Correct! / Wrong! ๋ฅผ ๋ฐ›์•„ ์˜ค๋ฉด ๊ทธ๋Ÿฐ ์ฐฉ๊ฐ์ด ๋‚„ ์ž๋ฆฌ๊ฐ€ ์—†๋‹ค.

๋ฐฉ์–ดํ•˜๋Š” ์ชฝ์—์„œ๋Š”, ํด๋ผ์ด์–ธํŠธ์— ์ •๋‹ต์„ ๋„ฃ์–ด ๋‘๊ณ  ๋น„๊ตํ•˜๋Š” ๊ตฌ์กฐ ์ž์ฒด๊ฐ€ ๊ทผ๋ณธ ๋ฌธ์ œ๋‹ค. ๋ฐ”์ดํŠธ์ฝ”๋“œ๋กœ ์ ‘๋“  XOR ๋กœ ๊ฐ€๋ฆฌ๋“  ์‹คํ–‰ ์‹œ์ ์—๋Š” ๋ณต์›๋ผ์•ผ ํ•˜๋ฏ€๋กœ ์‹œ๊ฐ„๋งŒ ๋ฒŒ ๋ฟ์ด๋‹ค. ๊ฒ€์ฆ์ด ์‹ค์ œ๋กœ ํ•„์š”ํ•œ ๊ฐ’์ด๋ผ๋ฉด ๋น„๊ต๋ฅผ ์„œ๋ฒ„์—์„œ ํ•˜๊ฑฐ๋‚˜, ์ตœ์†Œํ•œ ์ •๋‹ต์„ ์ €์žฅํ•˜์ง€ ๋ง๊ณ  ์ž…๋ ฅ์˜ ํ•ด์‹œ๋งŒ ๋Œ€์กฐํ•˜๋Š” ์ชฝ์œผ๋กœ ๊ฐ€๋Š” ๊ฒŒ ๋งž๋‹ค.

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

Comments

๋Œ“๊ธ€

0๊ฐœ

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

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

Related

๊ด€๋ จ ๊ธ€

3๊ฐœ
[๐Ÿฅ‰ 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 +6
[๐Ÿฅ‡ Gold 4] ์•ˆํ‹ฐ๋””๋ฒ„๊น…์ด ์Šค์Šค๋กœ ๋ฌด๋„ˆ์ง€๋Š” ์ž๋ฆฌ โ€” DreamHack ptrace_block ํ’€์ด
blog

[๐Ÿฅ‡ Gold 4] ์•ˆํ‹ฐ๋””๋ฒ„๊น…์ด ์Šค์Šค๋กœ ๋ฌด๋„ˆ์ง€๋Š” ์ž๋ฆฌ โ€” DreamHack ptrace_block ํ’€์ด

์ƒ์„ฑ์ž๊ฐ€ AES-128 ํ‚ค๋ฅผ ๋งŒ๋“ค๊ณ  main ์€ ๊ทธ ํ‚ค๋กœ ์ž…๋ ฅ์„ ์•”ํ˜ธํ™”ํ•ด out.txt ์— ์“ด๋‹ค. ํ‚ค๋ฅผ ํ”๋“œ๋Š” ๊ฐ’์€ ptrace(PTRACE_TRACEME) ์˜ ๋ฐ˜ํ™˜๊ฐ’์„ 4096 ๋ฒˆ ๊ณฑํ•ด ๋งŒ๋“œ๋Š”๋ฐ, 32๋น„ํŠธ ๊ณฑ์…ˆ์ด ๋„˜์ณ ๋””๋ฒ„๊ฑฐ๊ฐ€ ์žˆ๋“  ์—†๋“  0 ์ด ๋œ๋‹ค. ๋‚จ์€ ๊ฑด ํ•˜์œ„ 1๋ฐ”์ดํŠธ์งœ๋ฆฌ XOR ๋ฟ์ด๋ผ 256 ๋ฒˆ ์‹œ๋„๋กœ ๋๋‚œ๋‹ค.
#dreamhack#ctf#reversing+6
2026-08-07#dreamhack +6
[๐Ÿฅ‰ Bronze 3] stripped Rust ๋ฐ”์ด๋„ˆ๋ฆฌ์—์„œ ์Šคํƒ key ๋ฅผ ๋ฝ‘์•„ XOR ์—ญ์‚ฐ โ€” DreamHack Rusty Gyul ํ’€์ด
blog

[๐Ÿฅ‰ Bronze 3] stripped Rust ๋ฐ”์ด๋„ˆ๋ฆฌ์—์„œ ์Šคํƒ key ๋ฅผ ๋ฝ‘์•„ XOR ์—ญ์‚ฐ โ€” DreamHack Rusty Gyul ํ’€์ด

์‹ฌ๋ณผ์„ ๋ชจ๋‘ ๊ฑท์–ด๋‚ธ Rust ELF ํ•˜๋‚˜๊ฐ€ "ํ”Œ๋ž˜๊ทธ๋ฅผ ๋งž์ถฐ๋ด"๋ผ๊ณ  ํ•œ๋‹ค. ltrace ์—๋Š” strcmp ํ•˜๋‚˜ ์•ˆ ์žกํžˆ๊ณ  main ์€ ๊ป๋ฐ๊ธฐ๋ฟ์ด๋‹ค. ์ง„์งœ ๊ฒ€์‚ฌ ๋ฃจํ‹ด์„ ์–ด์…ˆ๋ธ”๋ฆฌ์—์„œ ์ฐพ์•„ ๋“ค์–ด๊ฐ€ ๋ณด๋ฉด, ์ž…๋ ฅ์„ trim ํ•œ ๋’ค ์Šคํƒ์— ์‹ค์–ด๋‘” 32๋ฐ”์ดํŠธ key ์™€ ํ•œ ๋ฐ”์ดํŠธ์”ฉ XOR ํ•ด์„œ ์ „๋ถ€ 0x55 ์ธ์ง€๋งŒ ๋ณธ๋‹ค. key ๋ฅผ ๊ทธ๋Œ€๋กœ ๋ฝ‘์•„ 0x55 ๋กœ ๋˜XOR ํ•˜๋ฉด ํ”Œ๋ž˜๊ทธ๊ฐ€ ๋‚˜์˜จ๋‹ค.
#dreamhack#ctf#reversing+5
2026-07-16#dreamhack +5