[๐Ÿฅ‡ Gold 4] ์ ํ”„๋„ ๋น„๊ต๋„ ์—†๋Š” VM ์—์„œ flag ๋ฅผ ๋˜๋ฝ‘๊ธฐ โ€” DreamHack bitvm ํ’€์ด

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

[๐Ÿฅ‡ Gold 4] ์ ํ”„๋„ ๋น„๊ต๋„ ์—†๋Š” VM ์—์„œ flag ๋ฅผ ๋˜๋ฝ‘๊ธฐ โ€” DreamHack bitvm ํ’€์ด

๋ช…๋ น์ด ์—ด ๊ฐœ๋ฟ์ธ ๋ฐ”์ดํŠธ์ฝ”๋“œ VM ์ด flag ๋ฅผ ๊ฒ€์‚ฌํ•œ๋‹ค. ๋ถ„๊ธฐ๋„ ๋น„๊ต๋„ ์‚ฐ์ˆ ๋„ ์—†๊ณ  ANDยทORยทXOR ๋งŒ ์žˆ๋‹ค. ๊ธ€์ž ํ•˜๋‚˜๋ฅผ ๊ฑฐ๋Š” ์ œ์•ฝ์ด (c & A) == B ์™€ (c | A) == C ๋‘ ์ค„์ด๋ผ, ๋น„ํŠธ๋ณ„๋กœ ์ชผ๊ฐœ๋ฉด c = (A & B) | (~A & C) ๋กœ ๋‹ต์ด ํ•˜๋‚˜์”ฉ ๋”ฑ ๋–จ์–ด์ง„๋‹ค. ๋ธŒ๋ฃจํŠธํฌ์Šค๋„ ์†”๋ฒ„๋„ ํ•„์š” ์—†์—ˆ๋‹ค.

๋ฌธ์ œ: DreamHack ์›Œ๊ฒŒ์ž„ โ€” bitvm ๋ถ„๋ฅ˜: reversing ๋‚œ์ด๋„: ๐Ÿฅ‡ Gold 4 FLAG: DH{bc42e3abb217fa4fd8b8991bc5a378d7dd4421fd887feb797eb759ca2d0d0e95}

๋ฌธ์ œ ์„ค๋ช…์ด ํ•œ ์ค„์ด๋‹ค.

๊ฐ„๋‹จํ•œ VM์ž…๋‹ˆ๋‹ค! ์ ํ”„, ๋น„๊ต์—ฐ์‚ฐ์ž, ์‹ฌ์ง€์–ด๋Š” ๋ง์…ˆ ๋บ„์…ˆ๋„ ์กด์žฌํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค!

๋ณดํ†ต ์ด๋Ÿฐ ๋ฌธ์žฅ์€ ๊ฒ์„ ์ฃผ๋ ค๊ณ  ์“ด๋‹ค. ์—ฌ๊ธฐ์„œ๋Š” ๋ฐ˜๋Œ€๋‹ค. ์—†๋Š” ๊ฒƒ๋“ค์„ ํ•˜๋‚˜์”ฉ ์ง€์›Œ ๋‚˜๊ฐ€๋ฉด ๋‚จ๋Š” ๊ฒŒ ๋„ˆ๋ฌด ์ ์–ด์„œ, ์˜คํžˆ๋ ค ๋‹ต์ด ํ•œ ์ค„ ์ˆ˜์‹์œผ๋กœ ๋–จ์–ด์ง„๋‹ค.


๋ฌธ์ œ ๊ฐœ์š”

ํ•ญ๋ชฉ๋‚ด์šฉ
๋ฌธ์ œ๋ช…bitvm
๋‚œ์ด๋„๐Ÿฅ‡ Gold 4
๋ถ„๋ฅ˜reversing
์ถœ์ฒ˜Dreamhack CTF Season 4 Round #10 (Div2)
์ œ๊ณต ํŒŒ์ผchall (ELF 64-bit PIE, stripped) ยท command (2,472๋ฐ”์ดํŠธ ๋ฐ”์ดํŠธ์ฝ”๋“œ)
์„œ๋ฒ„์—†์Œ โ€” ์˜คํ”„๋ผ์ธ ๋ฌธ์ œ
ํ•ต์‹ฌ ์ทจ์•ฝ์  / ๊ธฐ๋ฒ•๋น„ํŠธ์—ฐ์‚ฐ๋งŒ ๊ฐ€์ง„ VM ์˜ ๊ฒ€์‚ฌ์‹์„ ๋น„ํŠธ ๋‹จ์œ„๋กœ ๋ถ„ํ•ดํ•ด ์—ญ์‚ฐ

ํ’€์ด ํ๋ฆ„์€ ์…‹์œผ๋กœ ๋‚˜๋‰œ๋‹ค.

  1. chall ์˜ ๋””์ŠคํŒจ์น˜ ๋ฃจํ”„๋ฅผ ์ฝ์–ด ๋ช…๋ น ์ง‘ํ•ฉ ์—ด ๊ฐœ๋ฅผ ๋ณต์›ํ•œ๋‹ค.
  2. ๊ทธ ๋ช…๋ น ์ง‘ํ•ฉ์œผ๋กœ command ๋ฅผ ๋””์Šค์–ด์…ˆ๋ธ”ํ•ด ๊ฒ€์‚ฌ ๋ธ”๋ก 68๊ฐœ๋ฅผ ์ฐพ๋Š”๋‹ค.
  3. ๋ธ”๋ก์ด ๊ฑฐ๋Š” ์ œ์•ฝ ๋‘ ์ค„์„ ๋น„ํŠธ๋ณ„๋กœ ํ’€์–ด ๊ธ€์ž๋ฅผ ํ•˜๋‚˜์”ฉ ๊ฒฐ์ •ํ•œ๋‹ค.


๐Ÿงฉ ๋ฐฐ๊ฒฝ โ€” ๋ฐ”์ดํŠธ์ฝ”๋“œ VM ๋ฌธ์ œ๊ฐ€ ์š”๊ตฌํ•˜๋Š” ๊ฒƒ

๋ฆฌ๋ฒ„์‹ฑ ๋ฌธ์ œ์—์„œ VM ์ด ๋‚˜์˜ค๋ฉด ๋ถ„์„ ๋Œ€์ƒ์ด ๋‘ ๊ฒน์ด ๋œ๋‹ค.

๋ฐ”๊นฅ์€ ๋„ค์ดํ‹ฐ๋ธŒ x86-64 ๋ฐ”์ด๋„ˆ๋ฆฌ๋‹ค. ์ด ์•ˆ์—๋Š” "๋ช…๋ น์„ ํ•˜๋‚˜ ์ฝ์–ด์„œ ์ข…๋ฅ˜์— ๋”ฐ๋ผ ๊ฐˆ๋ผ์ง„๋‹ค"๋Š” ๋ฃจํ”„ ํ•˜๋‚˜๋งŒ ๋“ค์–ด ์žˆ๋‹ค. ์ง„์งœ ๋กœ์ง์€ ๊ทธ ๋ฃจํ”„๊ฐ€ ํ•ด์„ํ•˜๋Š” ๋ฐ์ดํ„ฐ ํŒŒ์ผ ์ชฝ์— ์žˆ๋‹ค.

๊ทธ๋ž˜์„œ ์ˆœ์„œ๊ฐ€ ์ •ํ•ด์ ธ ์žˆ๋‹ค. ๋ฐ”๊นฅ ๋ฃจํ”„๋ฅผ ์ฝ์–ด ๋ช…๋ น ์ง‘ํ•ฉ(ISA)์„ ํ™•์ •ํ•˜์ง€ ๋ชปํ•˜๋ฉด ์•ˆ์ชฝ ๋ฐ์ดํ„ฐ๋Š” ๊ทธ๋ƒฅ ๋ฌด์˜๋ฏธํ•œ ๋ฐ”์ดํŠธ ๋ฉ์–ด๋ฆฌ๋‹ค. ๋ฐ˜๋Œ€๋กœ ISA ๋งŒ ํ™•์ •๋˜๋ฉด ์•ˆ์ชฝ์€ ๋””์Šค์–ด์…ˆ๋ธ”๋Ÿฌ 30์ค„๋กœ ์ฝํžŒ๋‹ค.

์ด ๋ฌธ์ œ๊ฐ€ ์žฌ๋ฏธ์žˆ๋Š” ์ง€์ ์€ ISA ๊ฐ€ ์˜๋„์ ์œผ๋กœ ๋นˆ์•ฝํ•˜๋‹ค๋Š” ๊ฒƒ์ด๋‹ค. ๋ฌธ์ œ ์„ค๋ช…์ด ์—†๋‹ค๊ณ  ์ž๋ž‘ํ•œ ๊ฒƒ๋“ค โ€” ๋ถ„๊ธฐยท๋น„๊ตยท๋ง์…ˆ โ€” ์€ ๋ณดํ†ต "๊ฒ€์‚ฌ"๋ฅผ ์งค ๋•Œ ์ œ์ผ ๋จผ์ € ์“ฐ๋Š” ๋„๊ตฌ๋“ค์ด๋‹ค. ๊ทธ๊ฑธ ๋‹ค ๋นผ๊ณ ๋„ 68๊ธ€์ž๋ฅผ ๊ฒ€์‚ฌํ•˜๋ ค๋ฉด ๋ฐฉ๋ฒ•์ด ํ•˜๋‚˜๋กœ ์ขํ˜€์ง„๋‹ค. ๊ทธ ์ขํ˜€์ง„ ๋ฐฉ๋ฒ•์ด ๊ณง ์—ญ์‚ฐ ๊ณต์‹์ด ๋œ๋‹ค.


๐Ÿ”ฌ ์ •์ฐฐ โ€” ํŒŒ์ผ ๋‘ ๊ฐœ, ๊ทธ๋ฆฌ๊ณ  ์ธ์‚ฌ๋ง์ด ๋ฐ์ดํ„ฐ์— ๋ฐ•ํ˜€ ์žˆ๋‹ค

๋ฐฐํฌ๋ณธ์„ ํ’€๋ฉด ํŒŒ์ผ์ด ๋‘˜์ด๋‹ค. ์‹คํ–‰ ๊ฐ€๋Šฅํ•œ chall ๊ณผ, file ์ด ๊ทธ๋ƒฅ data ๋ผ๊ณ  ๋‹ตํ•˜๋Š” command.

ls -l extracted/ && file extracted/* && checksec --file=extracted/chall
ls / file / checksec โ€” chall ์€ stripped PIE, command ๋Š” ์ •์ฒด๋ถˆ๋ช…์˜ data
ls / file / checksec โ€” chall ์€ stripped PIE, command ๋Š” ์ •์ฒด๋ถˆ๋ช…์˜ data

๋ณดํ˜ธ ๊ธฐ๋ฒ•์€ Full RELRO ยท Canary ยท NX ยท PIE ๋กœ ๋‹ค ์ผœ์ ธ ์žˆ๋‹ค. ํ•˜์ง€๋งŒ ์ด๊ฑด pwn ๋ฌธ์ œ๊ฐ€ ์•„๋‹ˆ๋ผ ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ๊นจ๋œจ๋ฆด ์ผ์ด ์—†๋‹ค. ์—ฌ๊ธฐ์„œ ์˜๋ฏธ ์žˆ๋Š” ๊ฑด stripped ํ•˜๋‚˜๋‹ค. ์‹ฌ๋ณผ์ด ์—†์œผ๋‹ˆ main ๋„ run ๋„ ์ด๋ฆ„์œผ๋กœ๋Š” ๋ชป ์ฐพ๋Š”๋‹ค.

๋จผ์ € ์•Œ์•„๋‘˜ ๊ฒƒ ํ•˜๋‚˜. chall ์€ ์ธ์ž ์—†์ด ์‹คํ–‰ํ•˜๋ฉด ์•„๋ฌด๊ฒƒ๋„ ์•ˆ ํ•œ๋‹ค.

// 0x1671 โ€” main
if (argc != 2) { puts("Usage: ./chall command_file"); return 0; }

๋ฐ”์ดํŠธ์ฝ”๋“œ ํŒŒ์ผ ๊ฒฝ๋กœ๋ฅผ ๋ฐ˜๋“œ์‹œ ๋„˜๊ฒจ์•ผ ํ•œ๋‹ค. ๊ทธ๋ƒฅ ./chall ๋งŒ ์น˜๊ณ  "์‹คํ–‰์ด ์•ˆ ๋˜๋„ค" ํ•˜๊ณ  ๋„˜์–ด๊ฐ€๊ธฐ ๋”ฑ ์ข‹์€ ์ง€์ ์ด๋ผ, ์‹คํ–‰์€ ๋Š˜ ์ด ๊ผด์ด์–ด์•ผ ํ•œ๋‹ค.

cd extracted && chmod +x chall && ./chall command

command ๋ฅผ ๋จผ์ € ๋“ค์—ฌ๋‹ค๋ดค๋‹ค.

xxd extracted/command | sed -n "1,6p;10,18p"
xxd โ€” ์•ž๋จธ๋ฆฌ์— 0x21 ์ด ๊ธ€์ž ์‚ฌ์ด์— ๋ผ์–ด ์žˆ๊ณ , ๋’ค๋กœ ๊ฐˆ์ˆ˜๋ก 0x23/0x25/0x26/0x27 ์ด ๋ฐ˜๋ณต๋œ๋‹ค
xxd โ€” ์•ž๋จธ๋ฆฌ์— 0x21 ์ด ๊ธ€์ž ์‚ฌ์ด์— ๋ผ์–ด ์žˆ๊ณ , ๋’ค๋กœ ๊ฐˆ์ˆ˜๋ก 0x23/0x25/0x26/0x27 ์ด ๋ฐ˜๋ณต๋œ๋‹ค

์—ฌ๊ธฐ์„œ ์ด๋ฏธ ์ ˆ๋ฐ˜์€ ๋ณด์ธ๋‹ค.

์•ž๋จธ๋ฆฌ ASCII ์—ด์ด !T!h!i!s! !i!s! ๋‹ค. ์›๋ณธ ๋ฌธ์ž์—ด์€ This is a mini VM to check the flag! ์ธ๋ฐ ๊ธ€์ž๋งˆ๋‹ค ์•ž์— 0x21(!)์ด ํ•˜๋‚˜์”ฉ ๋ผ์–ด ์žˆ๋‹ค. ์ฆ‰ 0x21 ์€ "๋‹ค์Œ ๋ฐ”์ดํŠธ๋ฅผ ์ถœ๋ ฅํ•˜๋ผ"๋Š” 1๋ฐ”์ดํŠธ ์˜คํผ๋žœ๋“œ ๋ช…๋ น์ด๋‹ค. ์ธ์‚ฌ๋ง์ด ์ฝ”๋“œ๊ฐ€ ์•„๋‹ˆ๋ผ ๋ช…๋ น ์‹œํ€€์Šค๋กœ ๋ฐ•ํ˜€ ์žˆ๋Š” ๊ฒƒ์ด๋‹ค.

๊ทธ ๋‹ค์Œ Input: ๋’ค๋กœ๋Š” 0x22(")๊ฐ€ ๊ธธ๊ฒŒ ์ด์–ด์ง„๋‹ค. ์ถœ๋ ฅ ๋‹ค์Œ์— ์˜ค๋Š” ๊ฒƒ์ด๋‹ˆ ์ž…๋ ฅ์„ ๋ฐ›๋Š” ๋ช…๋ น์ผ ๊ฐ€๋Šฅ์„ฑ์ด ๋†’๋‹ค. ๊ทธ๋ฆฌ๊ณ  ๊ทธ ๋’ค๋ถ€ํ„ฐ ํŒŒ์ผ ๋๊นŒ์ง€๋Š” 0x23 0x25 0x26 0x27 0x28 ์ด ์ผ์ •ํ•œ ๋ฆฌ๋“ฌ์œผ๋กœ ๋ฐ˜๋ณต๋œ๋‹ค. ๊ฒ€์‚ฌ ๋ฃจํ‹ด์ด ์—ฌ๊ธฐ ์žˆ๋‹ค.

์ถ”์ธก์€ ์—ฌ๊ธฐ๊นŒ์ง€๋‹ค. ๋‚˜๋จธ์ง€๋Š” ๋ฐ”๊นฅ ๋ฐ”์ด๋„ˆ๋ฆฌ๊ฐ€ ํ™•์ •ํ•ด ์ค€๋‹ค.


๐Ÿง  ๋ช…๋ น ์ง‘ํ•ฉ ๋ณต์› โ€” ๋””์ŠคํŒจ์น˜ ์ฒด์ธ์„ ๊ทธ๋Œ€๋กœ ์ฝ๋Š”๋‹ค

objdump -d ๋กœ ์ „์ฒด๋ฅผ ๋–  ๋†“์œผ๋ฉด 490์ค„์ฏค ๋‚˜์˜จ๋‹ค. stripped ๋ผ ํ•จ์ˆ˜ ์ด๋ฆ„์ด ์—†์ง€๋งŒ PLT ํ˜ธ์ถœ์€ ๊ทธ๋Œ€๋กœ ๋ณด์ด๋‹ˆ, ์–ด๋–ค ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ํ•จ์ˆ˜๋ฅผ ๋ถ€๋ฅด๋Š”์ง€๋กœ ์—ญํ• ์„ ์ง์ž‘ํ•  ์ˆ˜ ์žˆ๋‹ค.

.text ์•ˆ์—์„œ ์˜๋ฏธ ์žˆ๋Š” ๋ฉ์–ด๋ฆฌ๋Š” ๋‹ค์„ฏ์ด๋‹ค. ์•ž์ชฝ ์…‹์€ __cxa_finalize ๋ฅผ ๋งŒ์ง€๋Š” ์ปดํŒŒ์ผ๋Ÿฌ ์ƒ์„ฑ ์ฝ”๋“œ(frame_dummy ๋ฅ˜)๋ผ ๊ฑด๋„ˆ๋›ด๋‹ค. ๋‚จ์€ ๊ฒƒ ์ค‘ fopen / getc / feof ๋ฅผ ๋ถ€๋ฅด๋ฉฐ ๋ฐ”์ดํŠธ๋ฅผ .bss ๋กœ ํผ ๋‚˜๋ฅด๋Š” ๊ฒŒ ํŒŒ์ผ ๋กœ๋”๊ณ , putchar / getchar ๋ฅผ ๋ถ€๋ฅด๋ฉฐ ๋˜๋Œ์•„์˜ค๋Š” ์ ํ”„๊ฐ€ ์žˆ๋Š” ๊ฒŒ VM ๋ณธ์ฒด๋‹ค. ๋งˆ์ง€๋ง‰ ํ•˜๋‚˜๋Š” puts ๋‘ ๋ฒˆ์œผ๋กœ ํŒ์ •์„ ์ฐ๋Š” main ์ด๋‹ค.

๋กœ๋”๋ถ€ํ„ฐ ๋ณด์ž.

// 0x1229 โ€” command ํŒŒ์ผ์„ .bss 0x4040 ์œผ๋กœ ํ†ต์งธ ๋ณต์‚ฌ
FILE *f = fopen(path, "rb");
if (!f) { printf("No file named %s\n", path); return 1; }
for (int i = 0; !feof(f); i++) {
    if (i > 0x1387) { puts("Command too large"); return 1; }   // ์ตœ๋Œ€ 5000๋ฐ”์ดํŠธ
    code[i] = getc(f);
}

feof ๋ฅผ getc ์•ž์—์„œ ๊ฒ€์‚ฌํ•˜๋Š” ๊ตฌ์กฐ๋ผ, ๋งˆ์ง€๋ง‰ ํ•œ ๋ฒˆ์€ EOF(-1)๋ฅผ ๊ทธ๋Œ€๋กœ 0xff ๋กœ ์ €์žฅํ•˜๊ณ  ๋๋‚œ๋‹ค. command ๋Š” 2,472๋ฐ”์ดํŠธ์ด๊ณ  ๋งˆ์ง€๋ง‰ ๋ฐ”์ดํŠธ๊ฐ€ ๋งˆ์นจ HALT ๋ผ ์•„๋ฌด ์˜ํ–ฅ์ด ์—†๋‹ค. ์ฝ๋‹ค๊ฐ€ ๊ฐธ์›ƒํ–ˆ์ง€๋งŒ ํ•จ์ •์€ ์•„๋‹ˆ์—ˆ๋‹ค.

๊ทธ ๋‹ค์Œ ํ•จ์ˆ˜๊ฐ€ ๋ณธ์ฒด๋‹ค. 0x1341 ์—์„œ ์‹œ์ž‘ํ•ด 0x1364 ๋กœ ๋˜๋Œ์•„์˜ค๋Š” ๋ฃจํ”„ ํ•˜๋‚˜๊ฐ€ ์ „๋ถ€๋‹ค.

// 0x1341 โ€” ์ด๊ฒŒ VM ์ด๋‹ค
unsigned char regs[8] = {0};      // [rbp-0x10]
for (;;) {
    unsigned char op = code[pc];  // pc = .bss 0x6768
    pc++;
    if      (op == 0x20) return regs[0];
    else if (op == 0x21) { putchar(code[pc]); pc++; }
    ...
}

๋ถ„๊ธฐ ๊ตฌ์กฐ๊ฐ€ if-else 10๋‹จ์ด๋ผ cmp BYTE PTR [rbp-0x11], <์ƒ์ˆ˜> ๋งŒ ๋ฝ‘์œผ๋ฉด ์˜คํผ์ฝ”๋“œ ๋ชฉ๋ก์ด ๊ทธ๋Œ€๋กœ ๋‚˜์˜จ๋‹ค. ๊ฐ ์ค„์— ๋ฌด์Šจ ์ผ์„ ํ•˜๋Š”์ง€ ์ฃผ์„์„ ์–น์–ด ์ฐ์—ˆ๋‹ค. ์ฃผ์„์€ sed ๋กœ ๋‚ด๊ฐ€ ๋ถ™์ธ ๊ฒƒ์ด๊ณ  objdump ์›๋ž˜ ์ถœ๋ ฅ์—๋Š” ์—†๋‹ค.

# annot_dispatch.sed โ€” ์‹ค์ œ ์ถœ๋ ฅ์— ์„ค๋ช…๋งŒ ์–น๋Š”๋‹ค
s/cmp    BYTE PTR \[rbp-0x11\],0x20/&      <-- 0x20 HALT : r0 ์„ ๋ฐ˜ํ™˜๊ฐ’์œผ๋กœ/
s/cmp    BYTE PTR \[rbp-0x11\],0x21/&      <-- 0x21 PUTC : ๋‹ค์Œ ๋ฐ”์ดํŠธ๋ฅผ putchar/
s/cmp    BYTE PTR \[rbp-0x11\],0x22/&      <-- 0x22 READ : getchar ๊ฒฐ๊ณผ๋ฅผ ์Šคํƒ์— push/
s/cmp    BYTE PTR \[rbp-0x11\],0x23/&      <-- 0x23 SETI : r[a] = imm/
s/cmp    BYTE PTR \[rbp-0x11\],0x24/&      <-- 0x24 MOV  : r[a] = r[b]/
s/cmp    BYTE PTR \[rbp-0x11\],0x25/&      <-- 0x25 AND/
s/cmp    BYTE PTR \[rbp-0x11\],0x26/&      <-- 0x26 OR/
s/cmp    BYTE PTR \[rbp-0x11\],0x27/&      <-- 0x27 XOR/
s/cmp    BYTE PTR \[rbp-0x11\],0x28/&      <-- 0x28 POP  : r0 = pop()/
s/cmp    BYTE PTR \[rbp-0x11\],0x29/&      <-- 0x29 PUSH : push(r[a])/
objdump -d -M intel --start-address=0x1364 --stop-address=0x1670 extracted/chall | grep -E "cmp +BYTE PTR .rbp-0x11." | sed -f annot_dispatch.sed
objdump ์ •์  ๋ถ„์„ โ€” ๋””์ŠคํŒจ์น˜ ์ฒด์ธ์ด 0x20 ๋ถ€ํ„ฐ 0x29 ๊นŒ์ง€ ์ •ํ™•ํžˆ ์—ด ๋‹จ
objdump ์ •์  ๋ถ„์„ โ€” ๋””์ŠคํŒจ์น˜ ์ฒด์ธ์ด 0x20 ๋ถ€ํ„ฐ 0x29 ๊นŒ์ง€ ์ •ํ™•ํžˆ ์—ด ๋‹จ

์—ด ๊ฐœ๋‹ค. 0x20 ๋ถ€ํ„ฐ 0x29 ๊นŒ์ง€ ๋นˆํ‹ˆ์—†์ด ์ด์–ด์ง€๊ณ  ๊ทธ ๋ฐ–์˜ ๊ฐ’์€ ์•„๋ฌด ๋ถ„๊ธฐ์—๋„ ์•ˆ ๊ฑธ๋ ค ์กฐ์šฉํžˆ ๋ฌด์‹œ๋œ๋‹ค(๋ฃจํ”„ ๋งจ ๋์œผ๋กœ ๋–จ์–ด์ ธ ๋‹ค์‹œ fetch ๋กœ ๊ฐ„๋‹ค).

ALU ์ชฝ์€ ๋”ฐ๋กœ ๋ด์•ผ ํ•œ๋‹ค. 0x25 0x26 0x27 ์„ธ ํ•ธ๋“ค๋Ÿฌ๋Š” ์ฝ”๋“œ๊ฐ€ ๊ฑฐ์˜ ๋˜‘๊ฐ™๊ณ , ๋”ฑ ํ•œ ๋ช…๋ น๋งŒ ๋‹ค๋ฅด๋‹ค. ๋‘ ํ”ผ์—ฐ์‚ฐ์ž๋ฅผ esi ์™€ ecx ์— ๊ฐ๊ฐ ์‹ค์€ ๋‹ค์Œ ๊ทธ ๋‘˜์„ ํ•ฉ์น˜๋Š” ์ž๋ฆฌ๋‹ค.

# annot_alu.sed โ€” ๋ ˆ์ง€์Šคํ„ฐ ํŒŒ์ผ ์ ‘๊ทผ๊ณผ ์—ฐ์‚ฐ ์ž๋ฆฌ์— ์„ค๋ช…์„ ์–น๋Š”๋‹ค
s/and    esi,ecx/&        <-- 0x25 AND : r[a] \& r[b]/
s/or     esi,ecx/&        <-- 0x26 OR  : r[a] | r[b]/
s/xor    esi,ecx/&        <-- 0x27 XOR : r[a] ^ r[b]/
s/add    esi,ecx/&        <-- (์—†์Œ)/
s/sub    esi,ecx/&        <-- (์—†์Œ)/
s/movzx  esi,BYTE PTR \[rbp+rax\*1-0x10\]/&   <-- ์ฒซ์งธ ํ”ผ์—ฐ์‚ฐ์ž r[a] ์ฝ๊ธฐ/
s/movzx  ecx,BYTE PTR \[rbp+rax\*1-0x10\]/&   <-- ๋‘˜์งธ ํ”ผ์—ฐ์‚ฐ์ž r[b] ์ฝ๊ธฐ/
s/mov    BYTE PTR \[rbp+rax\*1-0x10\],dl/&      <-- ๊ฒฐ๊ณผ๋ฅผ r[d] ์— ์“ฐ๊ธฐ/
objdump -d -M intel --start-address=0x149f --stop-address=0x1610 extracted/chall | grep -E "(and|or|xor|add|sub) +esi,ecx|rbp.rax.1-0x10" | sed -f annot_alu.sed
objdump โ€” ๋‘ ๋ ˆ์ง€์Šคํ„ฐ๊ฐ€ ๋งŒ๋‚˜๋Š” ์ž๋ฆฌ๋Š” andยทorยทxor ์„ธ ๊ฐœ๋ฟ, add/sub ํŒจํ„ด์€ ํ•œ ์ค„๋„ ์•ˆ ๊ฑธ๋ฆฐ๋‹ค
objdump โ€” ๋‘ ๋ ˆ์ง€์Šคํ„ฐ๊ฐ€ ๋งŒ๋‚˜๋Š” ์ž๋ฆฌ๋Š” andยทorยทxor ์„ธ ๊ฐœ๋ฟ, add/sub ํŒจํ„ด์€ ํ•œ ์ค„๋„ ์•ˆ ๊ฑธ๋ฆฐ๋‹ค

andยทorยทxor ์…‹๋งŒ ๊ฑธ๋ฆฐ๋‹ค. ๊ฐ™์€ grep ์— addยทsub ๋ฅผ ๊ฐ™์ด ๋„ฃ์—ˆ๋Š”๋ฐ ๋งค์น˜๊ฐ€ ์—†๋‹ค. ๋ฌธ์ œ ์„ค๋ช…์ด ์ž๋ž‘ํ•œ ๊ทธ๋Œ€๋กœ๋‹ค.

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

op์ด๋ฆ„์˜คํผ๋žœ๋“œ๋™์ž‘
0x20HALTโ€”r0 ์„ ๋ฐ˜ํ™˜๊ฐ’์œผ๋กœ ์ข…๋ฃŒ
0x21PUTCimmputchar(imm)
0x22READโ€”push(getchar())
0x23SETId, immr[d] = imm
0x24MOVd, sr[d] = r[s]
0x25ANDd, a, br[d] = r[a] & r[b]
0x26ORd, a, br[d] = r[a] | r[b]
0x27XORd, a, br[d] = r[a] ^ r[b]
0x28POPโ€”r0 = pop()
0x29PUSHspush(r[s])

์ƒํƒœ๋Š” ์ „๋ถ€ ์ „์—ญ์ด๋‹ค. ์ฝ”๋“œ ๋ฒ„ํผ๊ฐ€ .bss 0x4040, pc ๊ฐ€ 0x6768, ๋ฐ์ดํ„ฐ ์Šคํƒ์ด 0x53e0, ์Šคํƒ ํฌ์ธํ„ฐ๊ฐ€ 0x676c. ๋ ˆ์ง€์Šคํ„ฐ๋งŒ ์˜ˆ์™ธ๋กœ run() ์˜ ์Šคํƒ ์ง€์—ญ๋ณ€์ˆ˜ [rbp-0x10] 8๋ฐ”์ดํŠธ๋‹ค.

bitvm ์‹คํ–‰ ๊ตฌ์กฐ โ€” ์ฝ”๋“œ/pc/์Šคํƒ/๋ ˆ์ง€์Šคํ„ฐ ๋ฐฐ์น˜์™€ ์—†๋Š” ๋ช…๋ น๋“ค
bitvm ์‹คํ–‰ ๊ตฌ์กฐ โ€” ์ฝ”๋“œ/pc/์Šคํƒ/๋ ˆ์ง€์Šคํ„ฐ ๋ฐฐ์น˜์™€ ์—†๋Š” ๋ช…๋ น๋“ค

๋ ˆ์ง€์Šคํ„ฐ ์ธ๋ฑ์Šค๋Š” ๋ฐ”์ดํŠธ์ฝ”๋“œ์—์„œ ๊ทธ๋Œ€๋กœ ์˜ค๋Š”๋ฐ ๊ฒฝ๊ณ„ ๊ฒ€์‚ฌ๊ฐ€ ์—†๋‹ค. 8 ์ด์ƒ์„ ์ฃผ๋ฉด ๋ฐ”๋กœ ๋’ค ์นด๋‚˜๋ฆฌ๋ฅผ ๋ฐŸ๋Š”๋‹ค. ์‹ค์ œ command ๊ฐ€ ์“ฐ๋Š” ์ตœ๋Œ€ ์ธ๋ฑ์Šค๋Š” 7 ์ด๋ผ ์ด๋ฒˆ์—” ์•„๋ฌด ์ผ๋„ ์•ˆ ์ผ์–ด๋‚œ๋‹ค.

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


๐Ÿ›  ๋””์Šค์–ด์…ˆ๋ธ”๋Ÿฌ โ€” 30์ค„์ด๋ฉด ์•ˆ์ชฝ์ด ๋‹ค ๋ณด์ธ๋‹ค

ISA ๊ฐ€ ํ™•์ •๋์œผ๋‹ˆ command ๋ฅผ ์ฝ๋Š” ๊ฑด ๊ธฐ๊ณ„์ ์ด๋‹ค. ๊ฐ ๋ช…๋ น์˜ ์˜คํผ๋žœ๋“œ ๊ธธ์ด๋งŒ ์•Œ๋ฉด ๋˜๋‹ˆ๊นŒ.

#!/usr/bin/env python3
"""bitvm - command ํŒŒ์ผ(VM ๋ฐ”์ดํŠธ์ฝ”๋“œ) ๋””์Šค์–ด์…ˆ๋ธ”๋Ÿฌ."""
import sys
 
code = open(sys.argv[1] if len(sys.argv) > 1 else "extracted/command", "rb").read()
 
pc = 0
out = []
while pc < len(code):
    at = pc
    op = code[pc]
    pc += 1
    if op == 0x20:
        out.append((at, "HALT", ()))
        break
    elif op == 0x21:
        out.append((at, "PUTC", (code[pc],)))
        pc += 1
    elif op == 0x22:
        out.append((at, "READ", ()))
    elif op == 0x23:
        out.append((at, "SETI", (code[pc], code[pc + 1])))
        pc += 2
    elif op == 0x24:
        out.append((at, "MOV", (code[pc], code[pc + 1])))
        pc += 2
    elif op in (0x25, 0x26, 0x27):
        name = {0x25: "AND", 0x26: "OR", 0x27: "XOR"}[op]
        out.append((at, name, (code[pc], code[pc + 1], code[pc + 2])))
        pc += 3
    elif op == 0x28:
        out.append((at, "POP", ()))
    elif op == 0x29:
        out.append((at, "PUSH", (code[pc],)))
        pc += 1
    else:
        out.append((at, "??? 0x%02x" % op, ()))
 
for at, name, args in out:
    if name == "PUTC":
        print("%04x  PUTC  0x%02x   ; %r" % (at, args[0], chr(args[0])))
    elif name == "SETI":
        print("%04x  SETI  r%d, 0x%02x" % (at, args[0], args[1]))
    elif name == "MOV":
        print("%04x  MOV   r%d, r%d" % (at, args[0], args[1]))
    elif name in ("AND", "OR", "XOR"):
        sym = {"AND": "&", "OR": "|", "XOR": "^"}[name]
        print("%04x  %-5s r%d, r%d, r%d   ; r%d = r%d %s r%d"
              % (at, name, args[0], args[1], args[2], args[0], args[1], sym, args[2]))
    elif name == "PUSH":
        print("%04x  PUSH  r%d" % (at, args[0]))
    else:
        print("%04x  %s" % (at, name))
 
print("\n์ด %d ๋ช…๋ น, READ %d ๊ฐœ, POP %d ๊ฐœ"
      % (len(out),
         sum(1 for _, n, _ in out if n == "READ"),
         sum(1 for _, n, _ in out if n == "POP")))

๋Œ๋ ค์„œ ์•ž๋’ค๋ฅผ ์ž˜๋ผ ๋ดค๋‹ค.

python3 disasm.py extracted/command | sed -n "41,50p;110,112p" && python3 disasm.py extracted/command | tail -4
disasm.py ์ถœ๋ ฅ โ€” ์ธ์‚ฌ๋ง PUTC ๋’ค๋กœ READ ๊ฐ€ 68๋ฒˆ, ๋์€ MOV r0, r7 ๊ณผ HALT
disasm.py ์ถœ๋ ฅ โ€” ์ธ์‚ฌ๋ง PUTC ๋’ค๋กœ READ ๊ฐ€ 68๋ฒˆ, ๋์€ MOV r0, r7 ๊ณผ HALT

์ด 794๋ช…๋ น. READ 68๊ฐœ, POP 68๊ฐœ. ์ž…๋ ฅ์„ 68๊ธ€์ž ๋ฐ›์•„์„œ 68๋ฒˆ ๊บผ๋‚ด ์“ด๋‹ค๋Š” ๋œป์ด๋‹ค. DH{ ์™€ } ๋ฅผ ๋นผ๋ฉด 64์ž โ€” ๋”ฑ SHA-256 ํ—ฅ์‚ฌ ๊ธธ์ด๋‹ค.

๊ทธ๋ฆฌ๊ณ  ๋งˆ์ง€๋ง‰ ๋‘ ์ค„์ด ๊ฒฐ๋ก ์„ ๋ฏธ๋ฆฌ ์•Œ๋ ค ์ค€๋‹ค.

09a4  MOV   r0, r7
09a7  HALT

r7 ์„ r0 ์— ์˜ฎ๊ธฐ๊ณ  ๋๋‚ธ๋‹ค. main ์€ ์ด ๋ฐ˜ํ™˜๊ฐ’์„ ์ด๋ ‡๊ฒŒ ์“ด๋‹ค.

// 0x16bf โ€” run() ์˜ ๋ฐ˜ํ™˜๊ฐ’์ด 0 ์ด์–ด์•ผ Correct
if (run() == 0) puts("Correct!!!");
else            puts("Wrong.");

์ฆ‰ r7 ์„ 0 ์œผ๋กœ ๋งŒ๋“œ๋Š” ์ž…๋ ฅ์ด flag ๋‹ค. r7 ์ด ๋ฌด์—‡์„ ๋ชจ์œผ๋Š”์ง€๋งŒ ๋ณด๋ฉด ๋œ๋‹ค.

๊ทธ ์ „์— ๋ช…๋ น์ด ๊ฐ๊ฐ ๋ช‡ ๋ฒˆ ์“ฐ์ด๋Š”์ง€ ์„ธ์–ด ๋ดค๋‹ค. ๋ฐ˜๋ณต ๊ตฌ์กฐ๋ผ๋ฉด ํšŸ์ˆ˜๊ฐ€ 68์˜ ๋ฐฐ์ˆ˜๋กœ ๋”ฑ ๋–จ์–ด์งˆ ๊ฒƒ์ด๊ณ , ์•ˆ ๋–จ์–ด์ง€๋ฉด ๋‚ด๊ฐ€ ์˜คํผ๋žœ๋“œ ๊ธธ์ด๋ฅผ ์ž˜๋ชป ์ฝ์—ˆ๋‹ค๋Š” ๋œป์ด๋‹ค. ๊ฐ’์‹ผ ์ž๊ฐ€ ์ง„๋‹จ์ด๋‹ค.

#!/usr/bin/env python3
"""command ๋ฐ”์ดํŠธ์ฝ”๋“œ๊ฐ€ ๊ฐ ๋ช…๋ น์„ ๋ช‡ ๋ฒˆ ์“ฐ๋Š”์ง€ ์„ผ๋‹ค."""
from collections import Counter
 
NAMES = {0x20: "HALT", 0x21: "PUTC", 0x22: "READ", 0x23: "SETI", 0x24: "MOV",
         0x25: "AND", 0x26: "OR", 0x27: "XOR", 0x28: "POP", 0x29: "PUSH"}
WIDTH = {0x20: 0, 0x21: 1, 0x22: 0, 0x23: 2, 0x24: 2,
         0x25: 3, 0x26: 3, 0x27: 3, 0x28: 0, 0x29: 1}
 
code = open("extracted/command", "rb").read()
cnt = Counter()
pc = 0
while pc < len(code):
    op = code[pc]
    cnt[op] += 1
    pc += 1 + WIDTH[op]
    if op == 0x20:
        break
 
WHY = {
    "HALT": "ํ”„๋กœ๊ทธ๋žจ ๋ ํ•œ ๋ฒˆ",
    "PUTC": "์ธ์‚ฌ๋ง 44๊ธ€์ž",
    "READ": "์ž…๋ ฅ 68๊ธ€์ž",
    "SETI": "๋ธ”๋ก๋‹น A,B,C  = 68 x 3",
    "MOV": "๋งˆ์ง€๋ง‰ r0 = r7 ํ•œ ๋ฒˆ",
    "AND": "๋ธ”๋ก๋‹น c & A  = 68 x 1",
    "OR": "c | A ์™€ r7 ๋ˆ„์  2ํšŒ = 68 x 3",
    "XOR": "B/C ์™€ ๋น„๊ต 2ํšŒ = 68 x 2",
    "POP": "๋ธ”๋ก๋‹น ๊ธ€์ž ํ•˜๋‚˜ = 68 x 1",
    "PUSH": "์ด ๋ฐ”์ดํŠธ์ฝ”๋“œ๋Š” ์•ˆ ์“ด๋‹ค",
}
 
print("op    ์ด๋ฆ„   ํšŸ์ˆ˜   ์„ค๋ช…")
for op in sorted(NAMES):
    n = NAMES[op]
    print("0x%02x  %-5s %4d   %s" % (op, n, cnt[op], WHY[n]))
print("\nํ•ฉ๊ณ„ %d ๋ช…๋ น / ํŒŒ์ผ %d ๋ฐ”์ดํŠธ" % (sum(cnt.values()), len(code)))

์˜ค๋ฅธ์ชฝ ์„ค๋ช… ์—ด์€ ๋‚ด๊ฐ€ ๋ถ™์ธ ๊ฒƒ์ด๋‹ค. ์ˆซ์ž๋งŒ ์Šคํฌ๋ฆฝํŠธ๊ฐ€ ์„ผ๋‹ค.

python3 opcount.py
opcount.py ์‹คํ–‰ โ€” SETI 204, OR 204, XOR 136 ์ด ์ „๋ถ€ 68์˜ ๋ฐฐ์ˆ˜๋กœ ๋–จ์–ด์ง„๋‹ค
opcount.py ์‹คํ–‰ โ€” SETI 204, OR 204, XOR 136 ์ด ์ „๋ถ€ 68์˜ ๋ฐฐ์ˆ˜๋กœ ๋–จ์–ด์ง„๋‹ค

์ „๋ถ€ 68์˜ ๋ฐฐ์ˆ˜๋‹ค. SETI 204 = 68 ร— 3, XOR 136 = 68 ร— 2, OR 204 = 68 ร— 3. ํŒŒ์‹ฑ์ด ์–ด๊ธ‹๋‚ฌ๋‹ค๋ฉด ์ด ์ˆซ์ž๋“ค์ด ์ง€์ €๋ถ„ํ•˜๊ฒŒ ๋‚˜์™”์„ ํ…๋ฐ ๊นจ๋—ํ•˜๋‹ค.

๋‘ ๊ฐ€์ง€๊ฐ€ ๋ˆˆ์— ๊ฑธ๋ฆฐ๋‹ค.

MOV ๊ฐ€ ๋”ฑ ํ•œ ๋ฒˆ๋ฟ์ด๋‹ค. ๋งˆ์ง€๋ง‰ MOV r0, r7 ์ด ๊ทธ ํ•˜๋‚˜๋‹ค. ๋ ˆ์ง€์Šคํ„ฐ ์‚ฌ์ด ๊ฐ’์„ ์˜ฎ๊ธธ ์ผ์ด ์—†๋‹ค๋Š” ๊ฑด ๋ธ”๋ก๋“ค์ด ์„œ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ์ฃผ๊ณ ๋ฐ›์ง€ ์•Š๋Š”๋‹ค๋Š” ๋œป โ€” ๊ธ€์ž๋งˆ๋‹ค ์™„์ „ํžˆ ๋…๋ฆฝ์ด๋‹ค.

PUSH ๋Š” ์•„์˜ˆ 0 ์ด๋‹ค. ISA ์—๋Š” ์žˆ๋Š”๋ฐ ์ด ๋ฐ”์ดํŠธ์ฝ”๋“œ๋Š” ํ•œ ๋ฒˆ๋„ ์•ˆ ์“ด๋‹ค. ์Šคํƒ์— ๊ฐ’์ด ์˜ฌ๋ผ๊ฐ€๋Š” ๊ฒฝ๋กœ๊ฐ€ READ ํ•˜๋‚˜๋ฟ์ด๋ผ๋Š” ๋œป์ด๊ณ , ๊ทธ๋ž˜์„œ ์Šคํƒ ๋‚ด์šฉ์€ ์ฒ˜์Œ๋ถ€ํ„ฐ ๋๊นŒ์ง€ "์ž…๋ ฅ 68๊ธ€์ž" ๊ทธ๋Œ€๋กœ๋‹ค. ์ด ์‚ฌ์‹ค์ด ๋’ค์—์„œ ์ˆœ์„œ๋ฅผ ํ™•์ •ํ•  ๋•Œ ์“ฐ์ธ๋‹ค.

PUTC 44 ๋„ ๋งž๋‹ค. This is a mini VM to check the flag! 36์ž + ๊ฐœํ–‰ + Input: 7์ž.

๊ฒ€์‚ฌ ๋ธ”๋ก์„ ๋‘ ๊ฐœ ๋‚˜๋ž€ํžˆ ์ฐ์—ˆ๋‹ค.

python3 disasm.py extracted/command | sed -n "113,132p"
disasm.py โ€” ๊ฒ€์‚ฌ ๋ธ”๋ก์€ SETI 3๊ฐœ + POP + ์—ฌ์„ฏ ์ค„ ์—ฐ์‚ฐ์ด ํ•œ ์„ธํŠธ๋กœ 68๋ฒˆ ๋ฐ˜๋ณต๋œ๋‹ค
disasm.py โ€” ๊ฒ€์‚ฌ ๋ธ”๋ก์€ SETI 3๊ฐœ + POP + ์—ฌ์„ฏ ์ค„ ์—ฐ์‚ฐ์ด ํ•œ ์„ธํŠธ๋กœ 68๋ฒˆ ๋ฐ˜๋ณต๋œ๋‹ค

๋ธ”๋ก ํ•˜๋‚˜๊ฐ€ ์—ด ์ค„์ด๊ณ , ์ƒ์ˆ˜ ์…‹๋งŒ ๋ฐ”๋€Œ๋ฉด์„œ 68๋ฒˆ ๋˜ํ’€์ด๋œ๋‹ค. ํ•œ ๋ฒŒ์„ ์˜ฎ๊ฒจ ์ ์œผ๋ฉด ์ด๋ ‡๋‹ค.

SETI r1, A          ; ๋ธ”๋ก๋งˆ๋‹ค ๋‹ค๋ฅธ ์ƒ์ˆ˜ ์…‹
SETI r2, B
SETI r3, C
POP                 ; r0 = ์ž…๋ ฅ ํ•œ ๊ธ€์ž c
AND  r4, r0, r1     ; r4 = c & A
XOR  r5, r2, r4     ; r5 = B ^ (c & A)
OR   r7, r5, r7     ; r7 |= r5
OR   r4, r0, r1     ; r4 = c | A
XOR  r5, r3, r4     ; r5 = C ^ (c | A)
OR   r7, r5, r7     ; r7 |= r5

XOR ๋กœ ์ฐจ์ด๋ฅผ ๋งŒ๋“ค๊ณ  OR ๋กœ ๋ชจ์€๋‹ค. ๋น„๊ต ๋ช…๋ น์ด ์—†์œผ๋‹ˆ ์ด๊ฒŒ "๊ฐ™๋‹ค"๋ฅผ ํ‘œํ˜„ํ•˜๋Š” ์œ ์ผํ•œ ๋ฐฉ๋ฒ•์ด๋‹ค. ์ฐจ์ด๊ฐ€ 0 ์ด๋ฉด XOR ๊ฒฐ๊ณผ๊ฐ€ 0 ์ด๊ณ , ํ•˜๋‚˜๋ผ๋„ ๋‹ค๋ฅด๋ฉด ๊ทธ ๋น„ํŠธ๊ฐ€ ์ผœ์ ธ์„œ r7 ์— ๋ˆŒ์–ด๋ถ™๋Š”๋‹ค. ํ•œ ๋ฒˆ ์ผœ์ง„ ๋น„ํŠธ๋Š” OR ๋กœ๋งŒ ์Œ“์ด๋‹ˆ ์ ˆ๋Œ€ ์•ˆ ๊บผ์ง„๋‹ค.

๊ทธ๋Ÿฌ๋‹ˆ r7 == 0 ์€ 68๊ฐœ ๋ธ”๋ก์ด ์ „๋ถ€ ์•„๋ž˜ ๋‘˜์„ ๋งŒ์กฑํ•œ๋‹ค๋Š” ๋œป์ด๋‹ค.

(c & A) == B     ๊ทธ๋ฆฌ๊ณ      (c | A) == C

๐Ÿ› ์‚ฝ์งˆ

โ–ถ๐Ÿ› ์‚ฝ์งˆ 1 โ€” AND ์ œ์•ฝ๋งŒ ๋ณด๊ณ  ๊ธ€์ž๋ฅผ ์ •ํ•˜๋ ค ํ–ˆ๋‹ค

๋ธ”๋ก์„ ์ฒ˜์Œ ์ฝ์—ˆ์„ ๋•Œ (c & A) == B ๊ฐ€ ๋ˆˆ์— ๋จผ์ € ๋“ค์–ด์™”๋‹ค. AND ๋งˆ์Šคํฌ์— ์ƒ์ˆ˜๋ฅผ ๋งž์ถ”๋Š” ์ „ํ˜•์ ์ธ ๊ผด์ด๋ผ ์—ฌ๊ธฐ์„œ ๋‹ต์ด ๋‚˜์˜ฌ ์ค„ ์•Œ์•˜๋‹ค.

์•ˆ ๋‚˜์˜จ๋‹ค. A ๊ฐ€ 0 ์ธ ๋น„ํŠธ์—์„œ๋Š” (c & A) ๊ฐ€ c ์™€ ๋ฌด๊ด€ํ•˜๊ฒŒ 0 ์ด๋ผ, ๊ทธ ์ž๋ฆฌ c ๋Š” ์•„๋ฌด ๊ฐ’์ด์–ด๋„ ์ œ์•ฝ์„ ํ†ต๊ณผํ•œ๋‹ค. ์ฒซ ๋ธ”๋ก๋งŒ ๋ด๋„ A = 0xf3 ์ด๋‹ˆ 0 ์ธ ๋น„ํŠธ๊ฐ€ ๋‘˜, ํ›„๋ณด๊ฐ€ ๋„ท์ด๋‹ค.

์–ผ๋งˆ๋‚˜ ํผ์ง€๋Š”์ง€ ์‹ค์ œ๋กœ ์„ธ์–ด ๋ดค๋‹ค.

#!/usr/bin/env python3
"""์‚ฝ์งˆ ์žฌํ˜„ โ€” AND ์ œ์•ฝ ํ•˜๋‚˜๋งŒ ๋ณด๋ฉด ๊ธ€์ž๊ฐ€ ์•ˆ ์ •ํ•ด์ง„๋‹ค."""
from solve import consts
 
total = 1
for i, (A, B, C) in enumerate(consts):
    free = bin((~A) & 0xFF).count("1")     # A ๊ฐ€ 0 ์ธ ๋น„ํŠธ = ๋ฏธ์ • ๋น„ํŠธ
    total *= 1 << free
    if i < 6:
        print("๋ธ”๋ก %2d: A=0x%02x B=0x%02x C=0x%02x  ๋ฏธ์ • ๋น„ํŠธ %d๊ฐœ -> ํ›„๋ณด %3d ๊ฐœ"
              % (i, A, B, C, free, 1 << free))
 
print("...")
print("AND ์ œ์•ฝ๋งŒ ์“ฐ๋ฉด ์ „์ฒด ํ›„๋ณด ์ˆ˜ = 2^%d" % (total.bit_length() - 1))
print("OR ์ œ์•ฝ๊นŒ์ง€ ๊ฑธ์–ด์•ผ c = (A & B) | (~A & C) ๋กœ ์œ ์ผํ•ด์ง„๋‹ค")
python3 naive_and_only.py
naive_and_only.py ์‹คํ–‰ โ€” AND ์ œ์•ฝ๋งŒ์œผ๋กœ๋Š” ํ›„๋ณด๊ฐ€ 2^272 ๊ฐœ๋กœ ํผ์ง„๋‹ค
naive_and_only.py ์‹คํ–‰ โ€” AND ์ œ์•ฝ๋งŒ์œผ๋กœ๋Š” ํ›„๋ณด๊ฐ€ 2^272 ๊ฐœ๋กœ ํผ์ง„๋‹ค

2^272. ๋ธŒ๋ฃจํŠธํฌ์Šค๋กœ ๊ฐˆ ๊ธธ์ด ์•„๋‹ˆ๋‹ค.

์—ฌ๊ธฐ์„œ ๋ฐฉํ–ฅ์„ ์ž˜๋ชป ์žก์œผ๋ฉด SMT ์†”๋ฒ„๋ฅผ ๊บผ๋‚ด๊ฒŒ ๋œ๋‹ค. ์‹ค์ œ๋กœ z3 ์— ๋‘ ์ œ์•ฝ์„ ๋‹ค ๋„ฃ์œผ๋ฉด ํ’€๋ฆฌ๊ธฐ๋Š” ํ•œ๋‹ค. ํ•˜์ง€๋งŒ ๊ทธ๊ฑด ํ•„์š” ์—†๋Š” ๋„๊ตฌ๋‹ค. ๋’ค์˜ OR ์ œ์•ฝ์ด ์ •ํ™•ํžˆ ์ด ๋นˆ์นธ๋งŒ ๋ฉ”์šฐ๋„๋ก ์งœ์—ฌ ์žˆ๋‹ค๋Š” ๊ฑธ ์•Œ์•„์ฑ„๋ฉด ์‚ฐ์ˆ  ๋‘ ๋ฒˆ์œผ๋กœ ๋๋‚œ๋‹ค.

โ–ถ๐Ÿ› ์‚ฝ์งˆ 2 โ€” ๋ธ”๋ก ์ˆœ์„œ๋Œ€๋กœ ์ด์–ด๋ถ™์˜€๋”๋‹ˆ flag ๊ฐ€ ๋’ค์ง‘ํ˜€ ๋‚˜์™”๋‹ค

0x28 POP ์„ "์ž…๋ ฅ ํ•œ ๊ธ€์ž๋ฅผ ๊ฐ€์ ธ์˜จ๋‹ค" ์ •๋„๋กœ ์ฝ๊ณ  ๋„˜์–ด๊ฐ€๋ฉด ๊ฑธ๋ฆฐ๋‹ค. ํ•ธ๋“ค๋Ÿฌ๋ฅผ ๋‹ค์‹œ ๋ณด๋ฉด ๋ถ„๋ช…ํžˆ ์Šคํƒ์ด๋‹ค.

// 0x1315 โ€” pop()
sp--;
return stack[sp];

0x22 READ ๊ฐ€ 68๊ธ€์ž๋ฅผ ์ˆœ์„œ๋Œ€๋กœ push ํ•˜๊ณ , 0x28 POP ์€ ๊ทธ ๋ฐ˜๋Œ€์ชฝ ๋๋ถ€ํ„ฐ ๊บผ๋‚ธ๋‹ค. ์ฒซ ๋ฒˆ์งธ ๊ฒ€์‚ฌ ๋ธ”๋ก์ด ์ƒ๋Œ€ํ•˜๋Š” ๊ฑด ์ž…๋ ฅ์˜ ๋งˆ์ง€๋ง‰ ๊ธ€์ž๋‹ค.

๋ธ”๋ก ์ˆœ์„œ ๊ทธ๋Œ€๋กœ ์ด์–ด๋ถ™์ด๋ฉด ์–ด๋–ป๊ฒŒ ๋˜๋Š”์ง€ ์ฐ์–ด ๋ดค๋‹ค.

#!/usr/bin/env python3
"""์‚ฝ์งˆ ์žฌํ˜„ โ€” POP ์ด ์Šคํƒ์ด๋ผ๋Š” ๊ฑธ ๋†“์น˜๋ฉด ์–ด๋–ป๊ฒŒ ๋˜๋‚˜."""
from solve import consts          # solve.py ์˜ ํŒŒ์‹ฑ ๊ฒฐ๊ณผ๋ฅผ ๊ทธ๋Œ€๋กœ ์žฌ์‚ฌ์šฉ
 
chars = [(A & B) | (~A & C) & 0xFF for A, B, C in consts]
 
print("๋ธ”๋ก ์ˆœ์„œ ๊ทธ๋Œ€๋กœ :", bytes(chars).decode())
print("๋’ค์ง‘์€ ๊ฒƒ        :", bytes(reversed(chars)).decode())
python3 naive_order.py
naive_order.py ์‹คํ–‰ โ€” ๋’ค์ง‘์ง€ ์•Š์œผ๋ฉด }59e0... ๋กœ ์‹œ์ž‘ํ•˜๋Š” ๊ฑฐ์šธ์ƒ์ด ๋‚˜์˜จ๋‹ค
naive_order.py ์‹คํ–‰ โ€” ๋’ค์ง‘์ง€ ์•Š์œผ๋ฉด }59e0... ๋กœ ์‹œ์ž‘ํ•˜๋Š” ๊ฑฐ์šธ์ƒ์ด ๋‚˜์˜จ๋‹ค

}59e0d0d2...cb{HD. ๋‹คํ–‰ํžˆ ์ด๊ฑด ํ‹ฐ๊ฐ€ ํ™• ๋‚œ๋‹ค. flag ๊ฐ€ DH{ ๋กœ ์‹œ์ž‘ํ•œ๋‹ค๋Š” ๊ฑธ ์•Œ๊ณ  ์žˆ์œผ๋‹ˆ ๊ฑฐ์šธ์ƒ์ด ๋‚˜์˜ค๋ฉด ๋ฐ”๋กœ ์•Œ์•„์ฑˆ๋‹ค. ์ฒซ ๋ธ”๋ก์˜ ์ƒ์ˆ˜ ์…‹(A=0xf3 B=0x71 C=0xff)์„ ์†์œผ๋กœ ํ’€์–ด 0x7d = } ๊ฐ€ ๋‚˜์˜ค๋Š” ๊ฑธ ํ™•์ธํ•˜๋Š” ๊ฒŒ ๋” ๋น ๋ฅธ ํ™•์‹ ์ด์—ˆ๋‹ค.

flag ํฌ๋งท์„ ๋ชจ๋ฅด๋Š” ๋ฌธ์ œ์˜€๋‹ค๋ฉด ์—ฌ๊ธฐ์„œ ํ•œ์ฐธ ํ—ค๋งธ์„ ๊ฒƒ์ด๋‹ค.



๐Ÿ’ฃ ํ•ต์‹ฌ โ€” ๋‘ ์ œ์•ฝ์ด ์„œ๋กœ์˜ ์‚ฌ๊ฐ์ง€๋Œ€๋ฅผ ์ •ํ™•ํžˆ ๋ฉ”์šด๋‹ค

(c & A) == B ์™€ (c | A) == C ๋ฅผ ๋น„ํŠธ ๋‹จ์œ„๋กœ ์ชผ๊ฐœ๋ฉด ๊ฒฝ์šฐ๊ฐ€ ๋‘˜๋ฟ์ด๋‹ค.

A ์˜ ๊ทธ ๋น„ํŠธ๊ฐ€ 1 ์ธ ๊ฒฝ์šฐ. AND ๋Š” c ๋ฅผ ๊ทธ๋Œ€๋กœ ํ†ต๊ณผ์‹œํ‚จ๋‹ค. (c & A) ์˜ ๊ทธ ์ž๋ฆฌ๋Š” c ์ด๋ฏ€๋กœ c ๋น„ํŠธ = B ๋น„ํŠธ๋กœ ๋ชป ๋ฐ•ํžŒ๋‹ค. ๋ฐ˜๋ฉด OR ์€ ๋ฌด์กฐ๊ฑด 1 ์„ ๋งŒ๋“ค์–ด c ์— ๋Œ€ํ•ด ์•„๋ฌด๊ฒƒ๋„ ์•ˆ ์•Œ๋ ค ์ค€๋‹ค. (๊ทธ๋ž˜์„œ A ๊ฐ€ 1 ์ธ ์ž๋ฆฌ์—์„œ C ๊ฐ€ 0 ์ด๋ฉด ๊ทธ ๋ธ”๋ก์€ ์• ์ดˆ์— ๋งŒ์กฑ ๋ถˆ๊ฐ€๋Šฅ์ด๋‹ค.)

A ์˜ ๊ทธ ๋น„ํŠธ๊ฐ€ 0 ์ธ ๊ฒฝ์šฐ. ์ด๋ฒˆ์—” ๋ฐ˜๋Œ€๋‹ค. AND ๋Š” ๋ฌด์กฐ๊ฑด 0 ์ด๋ผ c ์™€ ๋ฌด๊ด€ํ•˜๊ณ , OR ์ด c ๋ฅผ ๊ทธ๋Œ€๋กœ ํ†ต๊ณผ์‹œ์ผœ c ๋น„ํŠธ = C ๋น„ํŠธ๊ฐ€ ๋œ๋‹ค. (๋งˆ์ฐฌ๊ฐ€์ง€๋กœ A ๊ฐ€ 0 ์ธ ์ž๋ฆฌ์—์„œ B ๊ฐ€ 1 ์ด๋ฉด ๋งŒ์กฑ ๋ถˆ๊ฐ€๋Šฅ์ด๋‹ค.)

ํ‘œ๋กœ ์ •๋ฆฌํ•˜๋ฉด ์‚ฌ๊ฐ์ง€๋Œ€๊ฐ€ ์–ด๋–ป๊ฒŒ ์—‡๊ฐˆ๋ฆฌ๋Š”์ง€๊ฐ€ ํ•œ๋ˆˆ์— ๋ณด์ธ๋‹ค.

A ๋น„ํŠธ(c & A) ๊ฐ€ ์•Œ๋ ค ์ฃผ๋Š” ๊ฒƒ(c | A) ๊ฐ€ ์•Œ๋ ค ์ฃผ๋Š” ๊ฒƒc ๋น„ํŠธ ๊ฒฐ์ •
1c ๊ทธ๋Œ€๋กœ โ†’ B ๋น„ํŠธ์™€ ๊ฐ™์•„์•ผ ํ•จํ•ญ์ƒ 1 (์ •๋ณด ์—†์Œ)B ์—์„œ
0ํ•ญ์ƒ 0 (์ •๋ณด ์—†์Œ)c ๊ทธ๋Œ€๋กœ โ†’ C ๋น„ํŠธ์™€ ๊ฐ™์•„์•ผ ํ•จC ์—์„œ

์–ด๋А ๋น„ํŠธ๋ฅผ ์žก์•„๋„ ๋‘˜ ์ค‘ ์ •ํ™•ํžˆ ํ•˜๋‚˜๊ฐ€ ๊ฐ’์„ ํ™•์ •ํ•œ๋‹ค. ๊ฒน์น˜์ง€๋„ ์•Š๊ณ  ๋น„์ง€๋„ ์•Š๋Š”๋‹ค.

c = (A & B) | (~A & C)

์ฒซ ๋ธ”๋ก์˜ ์ƒ์ˆ˜๋กœ ๊ทธ๋ ค ๋ณด๋ฉด ์ด๋ ‡๊ฒŒ ๋œ๋‹ค.

๋น„ํŠธ ์ œ์•ฝ ์—ญ์‚ฐ โ€” A=1 ์ž๋ฆฌ๋Š” B ์—์„œ, A=0 ์ž๋ฆฌ๋Š” C ์—์„œ ๊ฐ€์ ธ์™€ c ๊ฐ€ ํ•˜๋‚˜๋กœ ์ •ํ•ด์ง„๋‹ค
๋น„ํŠธ ์ œ์•ฝ ์—ญ์‚ฐ โ€” A=1 ์ž๋ฆฌ๋Š” B ์—์„œ, A=0 ์ž๋ฆฌ๋Š” C ์—์„œ ๊ฐ€์ ธ์™€ c ๊ฐ€ ํ•˜๋‚˜๋กœ ์ •ํ•ด์ง„๋‹ค

A = 0xf3 ์€ 1111 0011. 1 ์ธ ์—ฌ์„ฏ ์ž๋ฆฌ๋Š” B = 0x71 ์—์„œ, 0 ์ธ ๋‘ ์ž๋ฆฌ๋Š” C = 0xff ์—์„œ ๊ฐ€์ ธ์˜จ๋‹ค. ์กฐ๋ฆฝํ•˜๋ฉด 0111 1101 = 0x7d = }. ์ฒซ ๋ธ”๋ก์ด ๋งˆ์ง€๋ง‰ ๊ธ€์ž๋ฅผ ๊ฒ€์‚ฌํ•œ๋‹ค๋Š” ๊ฒƒ๊ณผ ์ •ํ™•ํžˆ ๋งž์•„๋–จ์–ด์ง„๋‹ค.

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

์ด๋ž˜์„œ ๋ธŒ๋ฃจํŠธํฌ์Šค๋„ ์†”๋ฒ„๋„ ํ•„์š” ์—†๋‹ค. 68๊ธ€์ž ร— ์‚ฐ์ˆ  ๋‘ ๋ฒˆ, ๋์ด๋‹ค.


๐ŸŽฏ ๋Ÿฐํƒ€์ž„ ๊ฒ€์ฆ โ€” gdb ๋กœ r7 ์„ ์ง์ ‘ ๋ณธ๋‹ค

์ •์  ๋ถ„์„๋งŒ์œผ๋กœ "r7 ์ด ๋ˆ„์ ๊ธฐ๊ณ  0 ์ด์–ด์•ผ ํ•œ๋‹ค"๊นŒ์ง€ ์™”๋‹ค. ์‹ค์ œ๋กœ ๊ทธ๋Ÿฐ์ง€๋Š” ์‹คํ–‰ ์ค‘์— ๊ทธ ๋ฐ”์ดํŠธ๋ฅผ ๋ˆˆ์œผ๋กœ ๋ด์•ผ ํ™•์‹คํ•˜๋‹ค.

๋ฐ”์ด๋„ˆ๋ฆฌ๊ฐ€ stripped PIE ๋ผ ๋ธŒ๋ ˆ์ดํฌํฌ์ธํŠธ ์ฃผ์†Œ๋ฅผ ์†์œผ๋กœ ์“ธ ์ˆ˜ ์—†๋‹ค. ๋กœ๋“œ ๋ฒ ์ด์Šค๋ฅผ ๊ด€๋ก€๋กœ ๊ฐ€์ •ํ•˜๋Š” ๊ฒƒ๋„ ์œ„ํ—˜ํ•ด์„œ(ํ™˜๊ฒฝ์— ๋”ฐ๋ผ ์–ด๊ธ‹๋‚œ๋‹ค), starti ๋กœ ํ•œ ๋ฒˆ ๋„์šด ๋’ค info proc mappings ์—์„œ ์‹ค์ œ ์ฃผ์†Œ๋ฅผ ์ฝ์–ด ๊ณ„์‚ฐํ–ˆ๋‹ค.

set confirm off
set pagination off
set disable-randomization on
 
# stripped + PIE ๋ผ ๋กœ๋“œ ๋ฒ ์ด์Šค๋ฅผ ๊ด€๋ก€๋กœ ๊ฐ€์ •ํ•˜์ง€ ์•Š๋Š”๋‹ค.
# starti ๋กœ ํ•œ ๋ฒˆ ๋„์šด ๋’ค info proc mappings ์—์„œ ์‹ค์ œ ์ฃผ์†Œ๋ฅผ ์ฝ์–ด ๋ธŒ๋ ˆ์ดํฌํฌ์ธํŠธ๋ฅผ ๊ฑด๋‹ค.
starti extracted/command
python
import gdb
maps = gdb.execute("info proc mappings", to_string=True)
base = next(int(l.split()[0], 16) for l in maps.splitlines() if l.rstrip().endswith("/chall"))
print("PIE base           = 0x%x" % base)
print("run() ๋””์ŠคํŒจ์น˜ ๋ฃจํ”„ = 0x%x" % (base + 0x1364))
# 0x138f = 0x20(HALT) ๋ถ„๊ธฐ ์•ˆ, r0 ๋ฅผ ๋ฐ˜ํ™˜๊ฐ’์œผ๋กœ ์ฝ์–ด๋“ค์ด๋Š” ์ž๋ฆฌ
gdb.execute("break *0x%x" % (base + 0x138f))
end
 
printf "\n===== [1] ๋ณต์›ํ•œ flag ๋ฅผ ๋„ฃ์—ˆ์„ ๋•Œ =====\n"
run extracted/command < flag.txt
x/8xb $rbp-0x10
printf "r7(๋ˆ„์  ๋ถˆ์ผ์น˜) = 0x%02x  ->  r0(๋ฐ˜ํ™˜๊ฐ’) = 0x%02x\n", *(unsigned char*)($rbp-0x9), *(unsigned char*)($rbp-0x10)
continue
 
printf "\n===== [2] ๋Œ€์กฐ๊ตฐ: DH{aaa...a} ๋ฅผ ๋„ฃ์—ˆ์„ ๋•Œ =====\n"
run extracted/command < wrong.txt
x/8xb $rbp-0x10
printf "r7(๋ˆ„์  ๋ถˆ์ผ์น˜) = 0x%02x  ->  r0(๋ฐ˜ํ™˜๊ฐ’) = 0x%02x\n", *(unsigned char*)($rbp-0x9), *(unsigned char*)($rbp-0x10)
printf "main ์€ ์ด ๋ฐ˜ํ™˜๊ฐ’์ด 0 ์ผ ๋•Œ๋งŒ Correct!!! ๋ฅผ ์ถœ๋ ฅํ•œ๋‹ค\n"

flag.txt ๋Š” ๋ณต์›ํ•œ flag, wrong.txt ๋Š” ๊ฐ™์€ ๊ธธ์ด์˜ DH{aaa...a} ๋ฅผ ๊ฐœํ–‰ ์—†์ด ๋‹ด์€ ํŒŒ์ผ์ด๋‹ค.

gdb -q -batch -x verify.gdb ./extracted/chall 2>&1 | grep -v "Thread debugging\|libthread_db"
gdb ๋Ÿฐํƒ€์ž„ ๊ฒ€์ฆ โ€” ์ •๋‹ต์ด๋ฉด ๋ ˆ์ง€์Šคํ„ฐ ํŒŒ์ผ 8๋ฐ”์ดํŠธ ์ค‘ r7 ์ด 0x00, ์˜ค๋‹ต์ด๋ฉด 0x5f
gdb ๋Ÿฐํƒ€์ž„ ๊ฒ€์ฆ โ€” ์ •๋‹ต์ด๋ฉด ๋ ˆ์ง€์Šคํ„ฐ ํŒŒ์ผ 8๋ฐ”์ดํŠธ ์ค‘ r7 ์ด 0x00, ์˜ค๋‹ต์ด๋ฉด 0x5f

๋ ˆ์ง€์Šคํ„ฐ ํŒŒ์ผ 8๋ฐ”์ดํŠธ๊ฐ€ ๊ทธ๋Œ€๋กœ ์ฐํžŒ๋‹ค. ์ •๋‹ต ์ž…๋ ฅ์—์„œ๋Š” r0 ๋ถ€ํ„ฐ r7 ๊นŒ์ง€ 00 14 04 54 54 00 00 00 โ€” ๋งจ ๋ r7 ์ด 0x00 ์ด๊ณ , ๊ทธ๊ฒŒ r0 ์— ๋ณต์‚ฌ๋ผ ๋ฐ˜ํ™˜๋œ๋‹ค. ๋Œ€์กฐ๊ตฐ์—์„œ๋Š” 5f 14 04 54 54 00 00 5f ๋กœ r7 ์ด 0x5f ๋‹ค.

0x5f = 0101 1111. 68๊ธ€์ž๋ฅผ ํ›‘๋Š” ๋™์•ˆ ์—ฌ์„ฏ ๊ฐœ ๋น„ํŠธ ์ž๋ฆฌ์—์„œ ๋ถˆ์ผ์น˜๊ฐ€ ๋‚ฌ๋‹ค๋Š” ๋œป์ด๋‹ค. ๋ˆ„์ ๊ธฐ๊ฐ€ ์ง„์งœ OR ๋กœ๋งŒ ์Œ“์ธ๋‹ค๋Š” ๊ฒƒ๋„ ์ด ๊ฐ’์œผ๋กœ ํ™•์ธ๋œ๋‹ค โ€” ๊ฐœ๋ณ„ ๋ธ”๋ก์˜ ์ฐจ์ด๊ฐ€ ๊ฒน์ณ ๋ˆŒ์–ด๋ถ™์€ ํ•ฉ์ง‘ํ•ฉ์ด๋‹ค.

์ค‘๊ฐ„์˜ r1~r4 ์— ๋‚จ์€ ๊ฐ’(14 04 54 54)์€ ๋งˆ์ง€๋ง‰ ๋ธ”๋ก์˜ ์ž”์—ฌ๋ฌผ์ด๋‹ค. ๋””์Šค์–ด์…ˆ๋ธ” ๊ฒฐ๊ณผ ๋งจ ๋ ๋ธ”๋ก์ด SETI r1, 0x14 / SETI r2, 0x04 / SETI r3, 0x54 ์˜€์œผ๋‹ˆ ์ •ํ™•ํžˆ ์ผ์น˜ํ•œ๋‹ค. ์ •์ ์œผ๋กœ ์ฝ์€ ๊ฒƒ๊ณผ ์‹ค์ œ ์‹คํ–‰์ด ์–ด๊ธ‹๋‚˜์ง€ ์•Š์•˜๋‹ค๋Š” ๊ต์ฐจ ํ™•์ธ์ด ํ•˜๋‚˜ ๋” ๋ถ™์€ ์…ˆ์ด๋‹ค.


๐Ÿš€ Full Exploit

๋””์Šค์–ด์…ˆ๋ธ”๋Ÿฌ์™€ ๊ฐ™์€ ๋ฐฉ์‹์œผ๋กœ command ๋ฅผ ํ›‘๋˜, ์ด๋ฒˆ์—” SETI r1/r2/r3 ์„ธ ๊ฐœ๊ฐ€ ๋ชจ์ผ ๋•Œ๋งˆ๋‹ค ์ƒ์ˆ˜ ๋ฌถ์Œ์„ ํ•˜๋‚˜์”ฉ ๋ฝ‘๋Š”๋‹ค. ๊ทธ๋ฆฌ๊ณ  ๊ณต์‹์„ ์ ์šฉํ•œ ๋’ค ๋’ค์ง‘๋Š”๋‹ค.

#!/usr/bin/env python3
"""bitvm (Dreamhack, Gold 4 / reversing) - flag ์—ญ์‚ฐ.
 
command ๋ฐ”์ดํŠธ์ฝ”๋“œ๋Š” ๊ฒ€์‚ฌ ๋ธ”๋ก ํ•˜๋‚˜๋ฅผ ์ด๋ ‡๊ฒŒ ๋งŒ๋“ ๋‹ค.
 
    SETI r1, A ; SETI r2, B ; SETI r3, C
    POP                       ; r0 = ์ž…๋ ฅ ํ•œ ๊ธ€์ž c (์Šคํƒ์ด๋ผ LIFO)
    AND r4,r0,r1 ; XOR r5,r2,r4 ; OR r7,r5,r7    ; (c & A) ^ B ๋ฅผ r7 ์— ๋ˆ„์ 
    OR  r4,r0,r1 ; XOR r5,r3,r4 ; OR r7,r5,r7    ; (c | A) ^ C ๋ฅผ r7 ์— ๋ˆ„์ 
 
๋งˆ์ง€๋ง‰์— MOV r0, r7 / HALT ์ด๊ณ  main ์€ r0 == 0 ์ผ ๋•Œ๋งŒ "Correct!!!" ๋ฅผ ์ถœ๋ ฅํ•œ๋‹ค.
์ฆ‰ ๋ชจ๋“  ๋ธ”๋ก์ด ์•„๋ž˜ ๋‘˜์„ ๋™์‹œ์— ๋งŒ์กฑํ•ด์•ผ ํ•œ๋‹ค.
 
    (c & A) == B     and     (c | A) == C
 
๋น„ํŠธ๋ณ„๋กœ ๋ณด๋ฉด
    A_i = 1 -> (c&A)_i = c_i = B_i,  (c|A)_i = 1 = C_i
    A_i = 0 -> (c&A)_i = 0 = B_i,    (c|A)_i = c_i = C_i
๋”ฐ๋ผ์„œ c = (A & B) | (~A & C) ๋กœ ์œ ์ผํ•˜๊ฒŒ ๊ฒฐ์ •๋œ๋‹ค.
"""
import sys
 
PATH = sys.argv[1] if len(sys.argv) > 1 else "extracted/command"
code = open(PATH, "rb").read()
 
# --- 1) ๋ฐ”์ดํŠธ์ฝ”๋“œ์—์„œ (A, B, C) 3๊ฐœ์งœ๋ฆฌ SETI ๋ฌถ์Œ์„ ์ˆœ์„œ๋Œ€๋กœ ๋ฝ‘๋Š”๋‹ค ---
consts = []
pc = 0
pending = {}
while pc < len(code):
    op = code[pc]
    if op == 0x20:                      # HALT
        break
    elif op == 0x21:                    # PUTC imm
        pc += 2
    elif op == 0x22 or op == 0x28:      # READ / POP
        pc += 1
    elif op == 0x23:                    # SETI r, imm
        pending[code[pc + 1]] = code[pc + 2]
        pc += 3
    elif op == 0x24:                    # MOV d, s
        pc += 3
    elif op in (0x25, 0x26, 0x27):      # AND / OR / XOR  d, a, b
        pc += 4
    elif op == 0x29:                    # PUSH r
        pc += 2
    else:
        raise SystemExit("unknown opcode 0x%02x at 0x%x" % (op, pc))
 
    # r1,r2,r3 ์ด ๋‹ค ์ฑ„์›Œ์ง€๋ฉด ํ•œ ๋ธ”๋ก์˜ ์ƒ์ˆ˜ ์„ธํŠธ๊ฐ€ ์™„์„ฑ๋œ ๊ฒƒ
    if {1, 2, 3} <= pending.keys():
        consts.append((pending.pop(1), pending.pop(2), pending.pop(3)))
 
# --- 2) ๋น„ํŠธ ์ œ์•ฝ์„ ํ’€์–ด ๊ธ€์ž๋ฅผ ๋ณต์›ํ•œ๋‹ค ---
chars = []
for i, (A, B, C) in enumerate(consts):
    if B & ~A & 0xFF:                   # A=0 ์ธ ๋น„ํŠธ์—์„œ B ๋Š” ๋ฐ˜๋“œ์‹œ 0
        raise SystemExit("๋ธ”๋ก %d ๋ชจ์ˆœ: B ์— A=0 ๋น„ํŠธ๊ฐ€ ์ผœ์ ธ ์žˆ์Œ" % i)
    if (~C & A) & 0xFF:                 # A=1 ์ธ ๋น„ํŠธ์—์„œ C ๋Š” ๋ฐ˜๋“œ์‹œ 1
        raise SystemExit("๋ธ”๋ก %d ๋ชจ์ˆœ: C ์— A=1 ๋น„ํŠธ๊ฐ€ ๊บผ์ ธ ์žˆ์Œ" % i)
    c = (A & B) | (~A & C) & 0xFF
    assert (c & A) == B and (c | A) == C, i
    chars.append(c)
 
# POP ์€ LIFO โ€” ์ฒซ ๋ธ”๋ก์ด ๋งˆ์ง€๋ง‰ ์ž…๋ ฅ ๊ธ€์ž๋ฅผ ๊ฒ€์‚ฌํ•œ๋‹ค
flag = bytes(reversed(chars))
 
if __name__ == "__main__":
    print("๊ฒ€์‚ฌ ๋ธ”๋ก %d ๊ฐœ" % len(consts))
    print("FLAG:", flag.decode())

๋‘ ๊ตฐ๋ฐ๋ฅผ ์ผ๋ถ€๋Ÿฌ ๋ฐฉ์–ด์ ์œผ๋กœ ์งฐ๋‹ค.

๋ชจ์ˆœ ๊ฒ€์‚ฌ ๋‘ ์ค„์€ "์ด ๊ตฌ์กฐ๊ฐ€ ์ •๋ง ๋‚ด๊ฐ€ ์ฝ์€ ๊ทธ ๊ตฌ์กฐ์ธ๊ฐ€"๋ฅผ ์Šค์Šค๋กœ ํ™•์ธํ•˜๋Š” ์žฅ์น˜๋‹ค. A ๊ฐ€ 0 ์ธ ์ž๋ฆฌ์— B ๋น„ํŠธ๊ฐ€ ์ผœ์ ธ ์žˆ๊ฑฐ๋‚˜ A ๊ฐ€ 1 ์ธ ์ž๋ฆฌ์— C ๋น„ํŠธ๊ฐ€ ๊บผ์ ธ ์žˆ์œผ๋ฉด ๊ทธ ๋ธ”๋ก์€ ์–ด๋–ค c ๋กœ๋„ ๋งŒ์กฑ๋  ์ˆ˜ ์—†๋‹ค. 68๋ธ”๋ก ์ „๋ถ€ ์•ˆ ๊ฑธ๋ ธ์œผ๋‹ˆ ํ•ด์„์ด ๋งž์€ ๊ฒƒ์ด๋‹ค.

assert ๋Š” ๋ณต์›ํ•œ ๊ธ€์ž๋ฅผ ์›๋ž˜ ์ œ์•ฝ์— ๋„๋กœ ๋„ฃ์–ด ๋ณธ๋‹ค. ๊ณต์‹์„ ์˜ฎ๊ฒจ ์ ๋‹ค ํ‹€๋ฆฌ๋ฉด ์—ฌ๊ธฐ์„œ ์ฃฝ๋Š”๋‹ค.

python3 solve.py extracted/command
solve.py ์‹คํ–‰ โ€” ๊ฒ€์‚ฌ ๋ธ”๋ก 68๊ฐœ์—์„œ flag 68๊ธ€์ž๊ฐ€ ํ•œ ๋ฒˆ์— ๋ณต์›๋œ๋‹ค
solve.py ์‹คํ–‰ โ€” ๊ฒ€์‚ฌ ๋ธ”๋ก 68๊ฐœ์—์„œ flag 68๊ธ€์ž๊ฐ€ ํ•œ ๋ฒˆ์— ๋ณต์›๋œ๋‹ค

DH{bc42e3abb217fa4fd8b8991bc5a378d7dd4421fd887feb797eb759ca2d0d0e95}.

๋งˆ์ง€๋ง‰์€ ๋ฐฐํฌ๋œ ๋ฐ”์ด๋„ˆ๋ฆฌ์— ์ง์ ‘ ๋จน์—ฌ ํŒ์ •์„ ๋ฐ›๋Š”๋‹ค. ์˜ค๋‹ต ๋Œ€์กฐ๊ตฐ์„ ๊ฐ™์ด ๋Œ๋ ค์•ผ "๋ญ˜ ๋„ฃ์–ด๋„ Correct ๊ฐ€ ๋‚˜์˜ค๋Š” ๊ฒƒ ์•„๋‹Œ๊ฐ€"๋ผ๋Š” ์˜์‹ฌ์ด ์ •๋ฆฌ๋œ๋‹ค.

#!/usr/bin/env python3
"""๋ณต์›ํ•œ flag ๋ฅผ ์‹ค์ œ chall + command ์— ๋จน์—ฌ ํŒ์ •์„ ํ™•์ธํ•œ๋‹ค."""
import subprocess
 
FLAG = "DH{bc42e3abb217fa4fd8b8991bc5a378d7dd4421fd887feb797eb759ca2d0d0e95}"
WRONG = "DH{" + "a" * 64 + "}"
 
for label, s in (("๋ณต์›ํ•œ flag", FLAG), ("๋Œ€์กฐ๊ตฐ(์ „๋ถ€ a)", WRONG)):
    r = subprocess.run(["./chall", "command"], input=s,
                       capture_output=True, text=True, cwd="extracted")
    print("[%s] %s" % (label, s))
    print("    -> %s" % r.stdout.strip().splitlines()[-1])
python3 verify.py
verify.py ์‹คํ–‰ โ€” ๋ณต์›ํ•œ flag ๋Š” Correct!!!, ๋Œ€์กฐ๊ตฐ์€ Wrong.
verify.py ์‹คํ–‰ โ€” ๋ณต์›ํ•œ flag ๋Š” Correct!!!, ๋Œ€์กฐ๊ตฐ์€ Wrong.

๐Ÿ” ์žฌํ˜„

๋ฌธ์ œ ํด๋”์— ๋„ฃ์–ด ๋‘” ํ•œ ๋ฐฉ ์Šคํฌ๋ฆฝํŠธ๋‹ค. ์—ญ์‚ฐ โ†’ flag ์ถœ๋ ฅ โ†’ ๋ฐ”์ด๋„ˆ๋ฆฌ ํŒ์ •๊นŒ์ง€ ์Šค์Šค๋กœ ๋Œ€์กฐํ•˜๊ณ  โœ… PASS / โŒ FAIL ๋กœ ๋๋‚œ๋‹ค. ์˜คํ”„๋ผ์ธ ๋ฌธ์ œ๋ผ ์„œ๋ฒ„๊ฐ€ ํ•„์š” ์—†๊ณ , ๊ฒฐ์ •๋ก ์ ์ด๋ผ ํ•œ ๋ฒˆ์ด๋ฉด ๋œ๋‹ค.

#!/usr/bin/env bash
# bitvm (DreamHack Gold 4 / reversing) โ€” ํ•œ ๋ฐฉ ์žฌํ˜„.
#   command ๋ฐ”์ดํŠธ์ฝ”๋“œ ์—ญ์‚ฐ -> flag ์ถœ๋ ฅ -> ์‹ค์ œ chall ๋ฐ”์ด๋„ˆ๋ฆฌ๋กœ ํŒ์ •๊นŒ์ง€ ํ™•์ธ.
# ์˜คํ”„๋ผ์ธ ๋ฌธ์ œ๋ผ ๋ผ์ด๋ธŒ ์„œ๋ฒ„๊ฐ€ ํ•„์š” ์—†๋‹ค. ๊ฒฐ์ •๋ก ์ ์ด๋ผ 1ํšŒ ์‹คํ–‰์ด๋ฉด ๋๋‚œ๋‹ค.
set -eu
cd "$(dirname "$(readlink -f "$0")")"
 
EXPECT=$(python3 -c "import json;print(json.load(open('๋ฌธ์ œ.json'))['flag'])" 2>/dev/null || cat flag.txt 2>/dev/null || echo '')
 
chmod +x extracted/chall
 
OUT=$(timeout 120 python3 solve.py extracted/command 2>&1) || true
echo "$OUT"
 
FLAG=$(printf '%s' "$OUT" | grep -aoE 'DH\{[^}]+\}' | head -1)
if [ -z "$FLAG" ]; then
  echo; echo "โŒ FAIL (solve.py ๊ฐ€ flag ๋ฅผ ๋ฝ‘์ง€ ๋ชปํ–ˆ๋‹ค)"; exit 1
fi
 
# ๋ฐ”์ด๋„ˆ๋ฆฌ์— ์ง์ ‘ ๋จน์—ฌ Correct!!! ๊ฐ€ ๋‚˜์˜ค๋Š”์ง€ ๋…๋ฆฝ ๊ฒ€์ฆ
JUDGE=$(printf '%s' "$FLAG" | (cd extracted && ./chall command) | tail -1)
echo "ํŒ์ •: $JUDGE"
 
if echo "$JUDGE" | grep -q 'Correct!!!' && { [ -z "$EXPECT" ] || [ "$FLAG" = "$EXPECT" ]; }; then
  echo; echo "โœ… PASS  $FLAG"; exit 0
fi
echo; echo "โŒ FAIL (์–ป์€ ๊ฐ’: '${FLAG:-์—†์Œ}' / ๊ธฐ๋Œ€: '$EXPECT' / ํŒ์ •: '$JUDGE')"; exit 1

๋กœ์ปฌ ํ™˜๊ฒฝ์€ ํŠน๋ณ„ํ•œ ๊ฒŒ ์—†๋‹ค. python3 ์™€ objdump(binutils), ๋Ÿฐํƒ€์ž„ ๊ฒ€์ฆ์šฉ gdb ๋ฉด ๋œ๋‹ค. chall ์€ ํ‰๋ฒ”ํ•œ ๋™์  ๋งํฌ x86-64 ELF ๋ผ ์š”์ฆ˜ ๋ฐฐํฌํŒ์—์„œ ๊ทธ๋Œ€๋กœ ๋ˆ๋‹ค.



๐Ÿ“ ๊ฒฐ๋ก 

์—†๋Š” ๋ช…๋ น์ด ๊ณง ์„ค๊ณ„๋„๋‹ค.

VM ๋ฌธ์ œ๋ฅผ ๋งŒ๋‚˜๋ฉด ๋ณดํ†ต "๋ฌด์Šจ ๋ช…๋ น์ด ์žˆ๋‚˜"๋ถ€ํ„ฐ ์„ผ๋‹ค. ์ด๋ฒˆ์—” ๋ฐ˜๋Œ€์ชฝ์ด ํ›จ์”ฌ ๋งŽ์€ ๊ฑธ ์•Œ๋ ค ์คฌ๋‹ค. ๋ถ„๊ธฐ๊ฐ€ ์—†๋‹ค๋Š” ๊ฑด ์ฝ”๋“œ๊ฐ€ ์ง์„ ์ด๋ผ๋Š” ๋œป์ด๊ณ , ์ง์„ ์ด๋ฉด 68๊ธ€์ž ๊ฒ€์‚ฌ๋Š” 68๋ฒŒ ํŽผ์ณ์ง„ ๋ฐ˜๋ณต ํŒจํ„ด์ผ ์ˆ˜๋ฐ–์— ์—†๋‹ค. ๋น„๊ต๊ฐ€ ์—†๋‹ค๋Š” ๊ฑด "๊ฐ™๋‹ค"๋ฅผ XOR ๋กœ ํ‘œํ˜„ํ–ˆ๋‹ค๋Š” ๋œป์ด๊ณ , XOR ๊ฒฐ๊ณผ๋ฅผ ๋ชจ์œผ๋ ค๋ฉด OR ๋ˆ„์ ๊ธฐ ๋ง๊ณ  ์“ธ ๊ฒŒ ์—†๋‹ค. ๋ช…๋ น ํ‘œ๋ฅผ ๋‹ค ๋ฝ‘๊ธฐ๋„ ์ „์— ์•ˆ์ชฝ ๊ตฌ์กฐ๊ฐ€ ์ ˆ๋ฐ˜์€ ์˜ˆ์ธก๋๋‹ค.

์ •๋ณด๋ฅผ ์žƒ๋Š” ์—ฐ์‚ฐ๋„ ์ง์„ ์ง€์œผ๋ฉด ์ •๋ณด๋ฅผ ์žƒ์ง€ ์•Š๋Š”๋‹ค.

c & A ๋Š” A ๊ฐ€ 0 ์ธ ๋น„ํŠธ๋ฅผ ๋ฒ„๋ฆฌ๊ณ , c | A ๋Š” A ๊ฐ€ 1 ์ธ ๋น„ํŠธ๋ฅผ ๋ฒ„๋ฆฐ๋‹ค. ๊ฐ๊ฐ์€ ๋˜๋Œ๋ฆด ์ˆ˜ ์—†์ง€๋งŒ ๋ฒ„๋ฆฌ๋Š” ์ž๋ฆฌ๊ฐ€ ์ •ํ™•ํžˆ ๋ฐ˜๋Œ€๋ผ์„œ, ๋‘˜์„ ๊ฒน์น˜๋ฉด ์›๋ณธ์ด ๊ทธ๋Œ€๋กœ ๋ณต์›๋œ๋‹ค. ๊ฒ€์‚ฌ๋ฅผ ํŠผํŠผํ•˜๊ฒŒ ๋งŒ๋“ค๋ ค๊ณ  ์ œ์•ฝ์„ ํ•˜๋‚˜ ๋” ์–น์€ ๊ฒƒ์ด ์˜คํžˆ๋ ค ๋‹ต์„ ์œ ์ผํ•˜๊ฒŒ ๋งŒ๋“ค์–ด ๋ฒ„๋ ธ๋‹ค. ๋‚œ๋…ํ™”์—์„œ ์ž์ฃผ ๋ณด๋Š” ์—ญ์„ค์ด๋‹ค.

๋งŒ๋“ค ๋•Œ๋Š” ์ด๋Ÿฐ ๊ฒ€์‚ฌ๋ฅผ ์“ฐ์ง€ ๋ง ๊ฒƒ.

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

stripped PIE ๋ฅผ gdb ๋กœ ๋ถ™์ผ ๋•Œ๋Š” ๋ฒ ์ด์Šค๋ฅผ ์ฝ์–ด์„œ ์“ด๋‹ค.

0x555555554000 ์€ ๊ด€๋ก€์ผ ๋ฟ ๋ณด์žฅ์ด ์•„๋‹ˆ๋‹ค. starti ๋กœ ๋„์šด ๋‹ค์Œ info proc mappings ์—์„œ ์‹ค์ œ ๊ฐ’์„ ๋ฝ‘์•„ ์˜คํ”„์…‹์„ ๋”ํ•˜๋Š” ๋ช‡ ์ค„์ด๋ฉด, ํ™˜๊ฒฝ์ด ๋ฐ”๋€Œ์–ด๋„ ๊ฐ™์€ ์Šคํฌ๋ฆฝํŠธ๊ฐ€ ๊ทธ๋Œ€๋กœ ๋ˆ๋‹ค. ์ด๋ฒˆ ๊ฒ€์ฆ ์Šคํฌ๋ฆฝํŠธ๊ฐ€ ๊ทธ๋ ‡๊ฒŒ ๋ผ ์žˆ๊ณ , ๋•๋ถ„์— ๋ธŒ๋ ˆ์ดํฌํฌ์ธํŠธ๋ฅผ ์†์œผ๋กœ ๊ณ ์น  ์ผ์ด ์—†์—ˆ๋‹ค.

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

Comments

๋Œ“๊ธ€

0๊ฐœ

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

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

Related

๊ด€๋ จ ๊ธ€

3๊ฐœ
[๐Ÿฅ‡ Gold 4] ์ง€๊ทธ์žฌ๊ทธ๋กœ ์ ‘ํžŒ ํ”Œ๋ž˜๊ทธ โ€” DreamHack quilt ํ’€์ด
blog

[๐Ÿฅ‡ Gold 4] ์ง€๊ทธ์žฌ๊ทธ๋กœ ์ ‘ํžŒ ํ”Œ๋ž˜๊ทธ โ€” DreamHack quilt ํ’€์ด

๋ฐฐํฌ๋œ quilt๋Š” ํ”Œ๋ž˜๊ทธ๋ฅผ ๊ฒ€์‚ฌํ•˜๋Š” ํ”„๋กœ๊ทธ๋žจ์ด ์•„๋‹ˆ๋ผ ํ”Œ๋ž˜๊ทธ๋ฅผ ๊ทธ๋ฆผ์œผ๋กœ ๊ตฝ๋Š” ์ธ์ฝ”๋”์˜€๋‹ค. /dev/urandom 192๋ฐ”์ดํŠธ ํ•œ๋ณตํŒ์— ์ธ์ž๋ฅผ ๊ทธ๋Œ€๋กœ ์–น๊ณ , 6๋น„ํŠธ์”ฉ ์ž˜๋ผ 64์ƒ‰ ํŒ”๋ ˆํŠธ๋กœ 32ร—32 ๋ธ”๋ก์„ ์น ํ•œ๋‹ค. ๋˜๋Œ๋ฆฌ๋Š” ๊ธธ๋ชฉ์— ๋†“์ธ ํ•จ์ •์€ ํ™€์ˆ˜ ๊ฒฉ์žํ–‰์„ ์ขŒ์šฐ๋กœ ๋’ค์ง‘๋Š” ํ•œ ์ค„์ด๋‹ค.
#dreamhack#ctf#reversing+4
2026-08-20#dreamhack +5
[๐Ÿฅ‰ Bronze 2] .rodata 247๋ฐ”์ดํŠธ๊ฐ€ ์Šคํƒ VM ๋ฐ”์ดํŠธ์ฝ”๋“œ์˜€๋‹ค โ€” DreamHack SelfStatus ํ’€์ด
blog

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

ํ”„๋กœ๊ทธ๋žจ์ด ์ž๊ธฐ /proc/self/status ๋ฅผ ์ฝ์–ด TracerPid ๋กœ ๋””๋ฒ„๊ฑฐ๋ฅผ ์•Œ์•„์ฑ„๊ณ  ์กฐ์šฉํžˆ ์ฃฝ๋Š”๋‹ค. ์ง„์งœ ๊ฒ€์‚ฌ๋Š” .rodata ์— ๋ฐ•ํžŒ 247๋ฐ”์ดํŠธ๋ฅผ ๋„๋Š” ์Šคํƒ VM ์ด ๋งก๋Š”๋ฐ, ๊ทธ VM ์€ ์‚ฌ์šฉ์ž ์ž…๋ ฅ์„ ์•„์˜ˆ ์ณ๋‹ค๋ณด์ง€ ์•Š๊ณ  ์ •๋‹ต ๋ฌธ์ž์—ด์„ ์Šค์Šค๋กœ ์กฐ๋ฆฝํ•œ๋‹ค. ๊ทธ๋ž˜์„œ ์—ญ์‚ฐํ•  ๊ฒƒ์ด ์—†๋‹ค โ€” VM ๋งŒ ์˜ฎ๊ฒจ ์ ์œผ๋ฉด ๋๋‚œ๋‹ค.
#dreamhack#ctf#reversing+6
2026-08-19#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