[๐Ÿฅˆ Silver 1] MixColumns ํ•˜๋‚˜๊ฐ€ ๋น ์ง€๋ฉด AES ๋Š” XOR ํ‘œ๋กœ ๋ฌด๋„ˆ์ง„๋‹ค โ€” DreamHack locked present ํ’€์ด

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

[๐Ÿฅˆ Silver 1] MixColumns ํ•˜๋‚˜๊ฐ€ ๋น ์ง€๋ฉด AES ๋Š” XOR ํ‘œ๋กœ ๋ฌด๋„ˆ์ง„๋‹ค โ€” DreamHack locked present ํ’€์ด

25๋ฐ”์ดํŠธ ๋น„๋ฐ€๋ฒˆํ˜ธ๋ฅผ ๊ฒ€์‚ฌํ•˜๋Š” stripped ELF ์•ˆ์— 5x5 ๋ธ”๋ก AES ๋ณ€ํ˜•์ด ํ†ต์งธ๋กœ ๋“ค์–ด ์žˆ๋‹ค. S-box ๋„ Rcon ๋„ ์ง„์งœ AES ์ธ๋ฐ MixColumns ๋งŒ ์—†๋‹ค. ๊ทธ ํ•˜๋‚˜๊ฐ€ ๋น ์ง€์ž ํ™•์‚ฐ์ด ์‚ฌ๋ผ์ ธ ํ‰๋ฌธ ๋ฐ”์ดํŠธ ํ•˜๋‚˜๊ฐ€ ์•”ํ˜ธ๋ฌธ ๋ฐ”์ดํŠธ ํ•˜๋‚˜๋กœ ๊ทธ๋Œ€๋กœ ๋Œ€์‘ํ–ˆ๊ณ , ๋ผ์šด๋“œ๊ฐ€ 10 ์ด๋ผ ์—ด ํšŒ์ „๋งˆ์ € ์ƒ์‡„๋ผ ์ž๋ฆฌ ์ˆœ์—ด๊นŒ์ง€ ํ•ญ๋“ฑ์ด ๋๋‹ค. ์žฌ๊ตฌํ˜„์œผ๋กœ ๋˜๊ฐ์•„ ๋น„๋ฐ€๋ฒˆํ˜ธ๋ฅผ ๋ณต๊ตฌํ•˜๊ณ , ํ‚ค๋ฅผ ์ „ํ˜€ ๋ชจ๋ฅด๋Š” ์ƒํƒœ์—์„œ๋„ ๊ฐ™์€ ๊ฐ’์ด ๋‚˜์˜ค๋Š” ๋‘ ๊ฐ€์ง€ ๊ฒฝ๋กœ๋ฅผ ๋”ฐ๋กœ ์‹ค์ฆํ–ˆ๋‹ค.

๋ฌธ์ œ: DreamHack โ€” locked present ๋ถ„๋ฅ˜: reversing ยท crypto ๋‚œ์ด๋„: ๐Ÿฅˆ Silver 1 FLAG: DH{W0w_U_kn0w_4b0ut_AES?}

๋ฌธ์ œ ์„ค๋ช…์€ ๋‘ ์ค„์ด ์ „๋ถ€๋‹ค. "์„ ๋ฌผ ์ƒ์ž๋Š” ์ž ๊ฒจ์žˆ์–ด ๋น„๋ฐ€๋ฒˆํ˜ธ๋ฅผ ์ž…๋ ฅํ•ด์•ผ๋งŒ ์—ด ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ž๋ฌผ์‡ ์˜ ํ”„๋กœ๊ทธ๋žจ์„ ๋ถ„์„ํ•˜์—ฌ ๋น„๋ฐ€๋ฒˆํ˜ธ๋ฅผ ์•Œ์•„๋‚ด์„ธ์š”."

๋ฐฐํฌ๋ณธ๋„ ํŒŒ์ผ ํ•˜๋‚˜๋ฟ์ด๋‹ค. 14KB ์งœ๋ฆฌ prob.

๋“œ๋ฆผํ•ต locked present ๋ฌธ์ œ ํŽ˜์ด์ง€ โ€” reversingยทcrypto ํƒœ๊ทธ๊ฐ€ ๊ฐ™์ด ๋ถ™์–ด ์žˆ๊ณ  ๋ฐฐํฌ ํŒŒ์ผ์€ prob ํ•˜๋‚˜๋ฟ์ด๋‹ค
๋“œ๋ฆผํ•ต locked present ๋ฌธ์ œ ํŽ˜์ด์ง€ โ€” reversingยทcrypto ํƒœ๊ทธ๊ฐ€ ๊ฐ™์ด ๋ถ™์–ด ์žˆ๊ณ  ๋ฐฐํฌ ํŒŒ์ผ์€ prob ํ•˜๋‚˜๋ฟ์ด๋‹ค

๋ฌธ์ œ ํŽ˜์ด์ง€ ๋งจ ์œ„์— "ํ•ด๋‹น ๋ฌธ์ œ๋Š” 2022 Christmas CTF ์— ์ถœ์ œ๋œ ๋ฌธ์ œ์ž…๋‹ˆ๋‹ค" ๋ผ๊ณ  ์ ํ˜€ ์žˆ๋‹ค. ๋‚˜์ค‘์— ๋‚˜์˜ค๋Š” ๋งˆ์Šคํ„ฐํ‚ค๊ฐ€ ์™œ ํฌ๋ฆฌ์Šค๋งˆ์Šค ์ธ์‚ฌ์ธ์ง€๋Š” ์—ฌ๊ธฐ์„œ ์ด๋ฏธ ์˜ˆ๊ณ ๋ผ ์žˆ๋Š” ์…ˆ์ด๋‹ค.


๋ฌธ์ œ ๊ฐœ์š”

ํ•ญ๋ชฉ๋‚ด์šฉ
๋ฌธ์ œ๋ช…locked present
๋‚œ์ด๋„๐Ÿฅˆ Silver 1
๋ถ„๋ฅ˜reversing ยท crypto
์ œ๊ณต ํŒŒ์ผprob (14,528 B ยท ELF 64-bit PIE ยท stripped)
์ŠคํƒC / glibc, gcc 9.4.0 (Ubuntu 20.04)
ํ•ต์‹ฌ ์ทจ์•ฝ์ AES ๋ผ์šด๋“œ ํ•จ์ˆ˜์—์„œ MixColumns ๋งŒ ๋น ์ ธ ํ™•์‚ฐ(diffusion)์ด 0

ํ’€์ด ํ๋ฆ„์€ ์ด๋ ‡๋‹ค. stripped ๋ฐ”์ด๋„ˆ๋ฆฌ์—์„œ ํ•จ์ˆ˜ ์ผ๊ณฑ ๊ฐœ๋ฅผ ๋ณต์›ํ•˜๋‹ˆ 5ร—5 ๋ธ”๋ก์„ ์“ฐ๋Š” AES ๋ณ€ํ˜•์ด ๋‚˜์˜จ๋‹ค. S-box ๋„ Rcon ๋„ ์ง„์งœ AES ํ‘œ๋ฅผ ๊ทธ๋Œ€๋กœ ์“ฐ๋Š”๋ฐ ๋ผ์šด๋“œ ํ•จ์ˆ˜์— MixColumns ๊ฐ€ ์—†๋‹ค. ๊ทธ ์ž๋ฆฌ๊ฐ€ ๋น„๋ฉด ์•”ํ˜ธ๊ฐ€ ๋ฐ”์ดํŠธ ๋‹จ์œ„๋กœ ์ชผ๊ฐœ์ง€๊ณ , ๋ผ์šด๋“œ ์ˆ˜๊ฐ€ 10 ์ด๋ผ ๋‚จ์€ ์—ด ํšŒ์ „๋งˆ์ € ์ƒ์‡„๋œ๋‹ค. ๋‚จ๋Š” ๊ฑด ์ž๋ฆฌ๋งˆ๋‹ค ๋…๋ฆฝ์ธ XOR ํ‘œ ํ•˜๋‚˜๋ฟ์ด๋ผ ๊ทธ๋ƒฅ ๊ฑฐ๊พธ๋กœ ๊ฐ์œผ๋ฉด ๋น„๋ฐ€๋ฒˆํ˜ธ๊ฐ€ ๋‚˜์˜จ๋‹ค.



๐Ÿงฉ ๋ฐฐ๊ฒฝ โ€” AES ๋ผ์šด๋“œ๊ฐ€ ํ•˜๋Š” ๋„ค ๊ฐ€์ง€

AES ์˜ ํ•œ ๋ผ์šด๋“œ๋Š” ๋„ค ๋‹จ๊ณ„๋‹ค. SubBytes ๋กœ ๋ฐ”์ดํŠธ๋ฅผ S-box ์— ํ†ต๊ณผ์‹œํ‚ค๊ณ , ShiftRows ๋กœ ํ–‰์„ ๋ฐ€๊ณ , MixColumns ๋กœ ์—ด์„ ์„ž๊ณ , AddRoundKey ๋กœ ๋ผ์šด๋“œํ‚ค๋ฅผ XOR ํ•œ๋‹ค.

์ด ์ค‘ MixColumns ๋ฅผ ๋บ€ ์…‹์€ ์ „๋ถ€ ์ž๋ฆฌ ๋‹จ์œ„๋กœ ๋…ผ๋‹ค. SubBytes ๋Š” ๋ฐ”์ดํŠธ ํ•˜๋‚˜๋ฅผ ๋ฐ”์ดํŠธ ํ•˜๋‚˜๋กœ ๋ฐ”๊พธ๊ณ , ShiftRows ๋Š” ์ž๋ฆฌ๋งŒ ์˜ฎ๊ธฐ๊ณ , AddRoundKey ๋Š” ๊ฐ™์€ ์ž๋ฆฌ๋ผ๋ฆฌ XOR ํ•œ๋‹ค. ์–ด๋А ๊ฒƒ๋„ ๋‘ ๋ฐ”์ดํŠธ๋ฅผ ์„ž์ง€ ์•Š๋Š”๋‹ค.

Wikimedia Commons ์˜ AES ShiftRows ๋„์‹ โ€” 4x4 ์ƒํƒœ์—์„œ ํ–‰ i ๋ฅผ ์™ผ์ชฝ์œผ๋กœ i ์นธ ํšŒ์ „์‹œํ‚จ๋‹ค. ์ž๋ฆฌ๋งŒ ์˜ฎ๊ธธ ๋ฟ ๊ฐ’์€ ๊ทธ๋Œ€๋กœ๋‹ค
Wikimedia Commons ์˜ AES ShiftRows ๋„์‹ โ€” 4x4 ์ƒํƒœ์—์„œ ํ–‰ i ๋ฅผ ์™ผ์ชฝ์œผ๋กœ i ์นธ ํšŒ์ „์‹œํ‚จ๋‹ค. ์ž๋ฆฌ๋งŒ ์˜ฎ๊ธธ ๋ฟ ๊ฐ’์€ ๊ทธ๋Œ€๋กœ๋‹ค

์ถœ์ฒ˜: Wikimedia Commons, Matt Crypto, public domain

๋ฐ”์ดํŠธ๋ฅผ ์‹ค์ œ๋กœ ์„ž๋Š” ๊ฑด MixColumns ํ•˜๋‚˜๋ฟ์ด๋‹ค. ์—ด ํ•˜๋‚˜๋ฅผ GF(2^8) ์œ„์˜ ๋‹คํ•ญ์‹ c(x) ์™€ ๊ณฑํ•ด์„œ, ๊ทธ ์—ด์˜ ๋„ค ๋ฐ”์ดํŠธ๊ฐ€ ์„œ๋กœ์—๊ฒŒ ๋ฒˆ์ง€๊ฒŒ ํ•œ๋‹ค.

Wikimedia Commons ์˜ AES MixColumns ๋„์‹ โ€” ์—ด ํ•˜๋‚˜๋ฅผ GF 2^8 ๋‹คํ•ญ์‹ c x ์™€ ๊ณฑํ•ด ๊ทธ ์—ด์˜ ๋„ค ๋ฐ”์ดํŠธ๋ฅผ ์„œ๋กœ ์„ž๋Š”๋‹ค
Wikimedia Commons ์˜ AES MixColumns ๋„์‹ โ€” ์—ด ํ•˜๋‚˜๋ฅผ GF 2^8 ๋‹คํ•ญ์‹ c x ์™€ ๊ณฑํ•ด ๊ทธ ์—ด์˜ ๋„ค ๋ฐ”์ดํŠธ๋ฅผ ์„œ๋กœ ์„ž๋Š”๋‹ค

์ถœ์ฒ˜: Wikimedia Commons, Matt Crypto, public domain

ShiftRows ์™€ MixColumns ๋ฅผ ํ•ฉ์ณ์•ผ ๋น„๋กœ์†Œ "๋‘ ๋ผ์šด๋“œ๋งŒ ์ง€๋‚˜๋ฉด ์ž…๋ ฅ ํ•œ ๋น„ํŠธ๊ฐ€ ์ถœ๋ ฅ ์ „์ฒด์— ์˜ํ–ฅ์„ ์ค€๋‹ค"๋Š” ์„ฑ์งˆ์ด ์„ ๋‹ค. ๋‘˜ ์ค‘ ํ•˜๋‚˜๋งŒ ๋น ์ ธ๋„ ๊ทธ๊ฒŒ ๋ฌด๋„ˆ์ง„๋‹ค.

์ด ๋ฌธ์ œ๊ฐ€ ์ •ํ™•ํžˆ ๊ทธ ์ด์•ผ๊ธฐ๋‹ค.


๐Ÿ”ฌ ์ •์ฐฐ โ€” ์‹ฌ๋ณผ ์—†๋Š” 14KB

๋จผ์ € ํŒŒ์ผ ์ •๋ณด์™€ ๋ˆˆ์— ๋„๋Š” ๋ฌธ์ž์—ด๋ถ€ํ„ฐ ๋ณธ๋‹ค.

file extracted/prob; nm extracted/prob; strings -n 5 extracted/prob | grep -nE "password|wrong|correct|merry"

fileยทnmยทstrings ๋กœ ๋ณธ prob โ€” PIE ์ด๊ณ  stripped ๋ผ ์‹ฌ๋ณผ์ด ์—†๋‹ค. ๋ฌธ์ž์—ด์€ input password ํ”„๋กฌํ”„ํŠธ์™€ wrongยทcorrect, ๊ทธ๋ฆฌ๊ณ  25๊ธ€์ž์งœ๋ฆฌ a_merry_christmas_for_you ๋„ท๋ฟ์ด๋‹ค
fileยทnmยทstrings ๋กœ ๋ณธ prob โ€” PIE ์ด๊ณ  stripped ๋ผ ์‹ฌ๋ณผ์ด ์—†๋‹ค. ๋ฌธ์ž์—ด์€ input password ํ”„๋กฌํ”„ํŠธ์™€ wrongยทcorrect, ๊ทธ๋ฆฌ๊ณ  25๊ธ€์ž์งœ๋ฆฌ a_merry_christmas_for_you ๋„ท๋ฟ์ด๋‹ค

PIE, stripped, ์‹ฌ๋ณผ 0๊ฐœ. ์“ธ ๋งŒํ•œ ๋ฌธ์ž์—ด์€ ๋„ท๋ฟ์ธ๋ฐ ๋งˆ์ง€๋ง‰์ด ๋ˆˆ์— ๊ฑธ๋ฆฐ๋‹ค. a_merry_christmas_for_you โ€” ์„ธ์–ด ๋ณด๋ฉด ์ •ํ™•ํžˆ 25๊ธ€์ž๋‹ค. ๋‚˜์ค‘์— ์ด๊ฒŒ ๊ทธ๋Œ€๋กœ ๋งˆ์Šคํ„ฐํ‚ค๋กœ ์“ฐ์ธ๋‹ค.

main ์€ ์ง„์ž…์ ์ด __libc_start_main ์— ๋„˜๊ธฐ๋Š” 0x1757 ์ด๋‹ค. ์•ž๋จธ๋ฆฌ๋ถ€ํ„ฐ ๋ณธ๋‹ค.

objdump -d -M intel extracted/prob --start-address=0x1775 --stop-address=0x17af | sed -E -f annot_main.sed

์ฃผ์„์€ ๋‚ด๊ฐ€ annot_main.sed ๋กœ ์–น์€ ๊ฒƒ์ด๊ณ , ๋‚˜๋จธ์ง€ ์ค„์€ objdump ์›๋ณธ ๊ทธ๋Œ€๋กœ๋‹ค. ์น˜ํ™˜ ๊ทœ์น™ ํŒŒ์ผ์€ ์ด๋ ‡๊ฒŒ ์ƒ๊ฒผ๋‹ค.

s|(mov    edi,0x113)|\1                    <-- 275 = 25๋ฐ”์ดํŠธ x ๋ผ์šด๋“œํ‚ค 11๊ฐœ|
s|(call   [0-9a-f]+ <malloc@plt>)|\1     <-- ๋ผ์šด๋“œํ‚ค ๋ฒ„ํผ|
s|(lea    rdi,\[rip\+0x9ad\].*)|\1  <-- "%s"|
s|(call   [0-9a-f]+ <__isoc99_scanf@plt>)|\1  <-- ์ž…๋ ฅ (๊ธธ์ด ๊ฒ€์‚ฌ ์—†์Œ)|
s|(call   1254 <exit@plt\+0x164>)|\1  <-- key_expand(rk, .data 0x4030)|
s|(call   16e2 <exit@plt\+0x5f2>)|\1  <-- encrypt(state, rk)|
s|(lea    rsi,\[rip\+0x27f8\].*)|\1  <-- ๋งˆ์Šคํ„ฐํ‚ค .data 0x4030|
s|(lea    rax,\[rip\+0x2756\].*)|\1  <-- ์ •๋‹ต ์•”ํ˜ธ๋ฌธ .data 0x4010|
s|(cmp    cl,al)|\1                       <-- ํ•œ ๋ฐ”์ดํŠธ์”ฉ ๋น„๊ต|
s|(je     18da <exit@plt\+0x7ea>)|\1  <-- ๊ฐ™์œผ๋ฉด ๋‹ค์Œ ๋ฐ”์ดํŠธ|
s|(call   [0-9a-f]+ <exit@plt>)|\1       <-- ์ฒซ ๋ถˆ์ผ์น˜์—์„œ ์ฆ‰์‹œ ์ข…๋ฃŒ|

objdump ๋กœ ๋ณธ main ์•ž๋จธ๋ฆฌ โ€” malloc 0x113 ์œผ๋กœ 275๋ฐ”์ดํŠธ ๋ฒ„ํผ๋ฅผ ์žก๊ณ  printf ๋กœ ํ”„๋กฌํ”„ํŠธ๋ฅผ ์ฐ์€ ๋’ค scanf %s ๋กœ ๊ธธ์ด ๊ฒ€์‚ฌ ์—†์ด ์ž…๋ ฅ์„ ๋ฐ›๋Š”๋‹ค
objdump ๋กœ ๋ณธ main ์•ž๋จธ๋ฆฌ โ€” malloc 0x113 ์œผ๋กœ 275๋ฐ”์ดํŠธ ๋ฒ„ํผ๋ฅผ ์žก๊ณ  printf ๋กœ ํ”„๋กฌํ”„ํŠธ๋ฅผ ์ฐ์€ ๋’ค scanf %s ๋กœ ๊ธธ์ด ๊ฒ€์‚ฌ ์—†์ด ์ž…๋ ฅ์„ ๋ฐ›๋Š”๋‹ค

malloc(0x113) = 275 ๋ฐ”์ดํŠธ. 25 ๋กœ ๋‚˜๋ˆ„๋ฉด 11 ์ด๋‹ค. 25๋ฐ”์ดํŠธ์งœ๋ฆฌ ๋ผ์šด๋“œํ‚ค 11๊ฐœ ๋ผ๊ณ  ์ฝ์œผ๋ฉด ๋ผ์šด๋“œ 10๊ฐœ์งœ๋ฆฌ ๋ธ”๋ก์•”ํ˜ธ๊ฐ€ ๋œ๋‹ค. ์ž…๋ ฅ์€ scanf("%s") ๋กœ ๊ธธ์ด ๊ฒ€์‚ฌ ์—†์ด ๋ฐ›๋Š”๋‹ค.

๊ทธ๋‹ค์Œ main ์€ ์ž…๋ ฅ 25๋ฐ”์ดํŠธ๋ฅผ ์Šคํƒ์˜ ๋‹ค๋ฅธ ๋ฒ„ํผ๋กœ 5ร—5 ๋กœ ์˜ฎ๊ธฐ๊ณ , ํ•จ์ˆ˜ ๋‘ ๊ฐœ๋ฅผ ๋ถ€๋ฅธ๋‹ค. ํ•˜๋‚˜๋Š” .data 0x4030 ์„ ์ธ์ž๋กœ ๋ฐ›๊ณ (ํ‚ค ํ™•์žฅ), ํ•˜๋‚˜๋Š” ๊ทธ ๊ฒฐ๊ณผ์™€ ์ƒํƒœ๋ฅผ ๋ฐ›๋Š”๋‹ค(์•”ํ˜ธํ™”). ์•”ํ˜ธํ™” ํ•จ์ˆ˜ 0x16e2 ๋ฅผ ์—ด์–ด ๋ณด๋ฉด ๊ตฌ์กฐ๊ฐ€ ๊ทธ๋Œ€๋กœ ๋“œ๋Ÿฌ๋‚œ๋‹ค.

objdump -d -M intel extracted/prob --start-address=0x16e2 --stop-address=0x1757 | sed -E -f annot_enc.sed
s|(mov    edi,0x0)|\1                     <-- ๋ผ์šด๋“œ 0|
s|(call   14a7 <exit@plt\+0x3b7>)|\1  <-- add_round_key|
s|(call   1572 <exit@plt\+0x482>)|\1  <-- sub_bytes  (S-box)|
s|(call   15fb <exit@plt\+0x50b>)|\1  <-- shift_cols (์—ด ํšŒ์ „)|
s|(cmp    BYTE PTR \[rbp-0x1\],0xa)|\1     <-- ๋ผ์šด๋“œ 1..10, MixColumns ์—†์Œ|

objdump ๋กœ ๋ณธ encrypt ํ•จ์ˆ˜ โ€” add_round_key ๋กœ ์‹œ์ž‘ํ•ด ๋ผ์šด๋“œ 1๋ถ€ํ„ฐ 10๊นŒ์ง€ sub_bytes ์™€ shift_cols ์™€ add_round_key ์„ธ ๊ฐœ๋งŒ ๋ถ€๋ฅธ๋‹ค. MixColumns ์ž๋ฆฌ์— ํ•ด๋‹นํ•˜๋Š” ๋„ค ๋ฒˆ์งธ ํ˜ธ์ถœ์ด ์—†๋‹ค
objdump ๋กœ ๋ณธ encrypt ํ•จ์ˆ˜ โ€” add_round_key ๋กœ ์‹œ์ž‘ํ•ด ๋ผ์šด๋“œ 1๋ถ€ํ„ฐ 10๊นŒ์ง€ sub_bytes ์™€ shift_cols ์™€ add_round_key ์„ธ ๊ฐœ๋งŒ ๋ถ€๋ฅธ๋‹ค. MixColumns ์ž๋ฆฌ์— ํ•ด๋‹นํ•˜๋Š” ๋„ค ๋ฒˆ์งธ ํ˜ธ์ถœ์ด ์—†๋‹ค

๋ผ์šด๋“œ ํ•˜๋‚˜์— call ์ด ์„ธ ๋ฒˆ๋ฟ์ด๋‹ค. 0x1572(SubBytes), 0x15fb(์ž๋ฆฌ ์ด๋™), 0x14a7(AddRoundKey). ๋„ค ๋ฒˆ์งธ๊ฐ€ ์—†๋‹ค. AES ๋ผ๋ฉด ์—ฌ๊ธฐ MixColumns ๊ฐ€ ์žˆ์–ด์•ผ ํ•œ๋‹ค.

0x15fb ์ด ๋ฌด์Šจ ์ž๋ฆฌ ์ด๋™์ธ์ง€ ํ™•์ธํ•œ๋‹ค.

objdump -d -M intel extracted/prob --start-address=0x1619 --stop-address=0x16ca | sed -E -f annot_cols.sed
s|(movzx  eax,BYTE PTR \[rdx\+rax\*1\])|\1        <-- t = st\[i\]|
s|(mov    BYTE PTR \[rdx\+rax\*1\],cl)$|\1        <-- st\[i\]    = st\[i+5\]|
s|(movzx  ecx,BYTE PTR \[rdx\+rax\*1\+0xa\])|\1  <-- st\[i+10\]|
s|(mov    BYTE PTR \[rdx\+rax\*1\+0x5\],cl)|\1   <-- st\[i+5\]  = st\[i+10\]|
s|(mov    BYTE PTR \[rdx\+rax\*1\+0xa\],cl)|\1   <-- st\[i+10\] = st\[i+15\]|
s|(mov    BYTE PTR \[rdx\+rax\*1\+0xf\],cl)|\1   <-- st\[i+15\] = st\[i+20\]|
s|(mov    BYTE PTR \[rdx\+rax\*1\+0x14\],cl)|\1  <-- st\[i+20\] = t|
s|(cmp    al,BYTE PTR \[rbp-0x3\])|\1            <-- ์•ˆ์ชฝ ๋ฃจํ”„๋ฅผ i ๋ฒˆ (์—ด i ๋Š” i ์นธ)|

objdump ๋กœ ๋ณธ shift_cols ๋ณธ์ฒด โ€” st i ๋ฅผ ์ €์žฅํ•ด ๋‘๊ณ  st i 5 10 15 20 ์„ ํ•œ ์นธ์”ฉ ๋‹น๊ธด ๋’ค ๋งˆ์ง€๋ง‰์— ๋˜๋Œ๋ ค ๋†“๋Š”๋‹ค. ์ƒํƒœ๊ฐ€ 5x5 ๋ผ ์ด ๋‹ค์„ฏ ์ž๋ฆฌ๋Š” ํ–‰์ด ์•„๋‹ˆ๋ผ ์—ด์ด๋‹ค
objdump ๋กœ ๋ณธ shift_cols ๋ณธ์ฒด โ€” st i ๋ฅผ ์ €์žฅํ•ด ๋‘๊ณ  st i 5 10 15 20 ์„ ํ•œ ์นธ์”ฉ ๋‹น๊ธด ๋’ค ๋งˆ์ง€๋ง‰์— ๋˜๋Œ๋ ค ๋†“๋Š”๋‹ค. ์ƒํƒœ๊ฐ€ 5x5 ๋ผ ์ด ๋‹ค์„ฏ ์ž๋ฆฌ๋Š” ํ–‰์ด ์•„๋‹ˆ๋ผ ์—ด์ด๋‹ค

๊ฑด๋“œ๋ฆฌ๋Š” ์˜คํ”„์…‹์ด i, i+5, i+10, i+15, i+20 ์ด๋‹ค. ์ƒํƒœ๋ฅผ st[5*ํ–‰ + ์—ด] ๋กœ ์žก์œผ๋ฉด ์ด ๋‹ค์„ฏ์€ ๊ฐ™์€ ์—ด์ด๋‹ค. ์ฆ‰ AES ์˜ ShiftRows ๋ฅผ ์ „์น˜ํ•œ ๋ชจ์–‘ โ€” ํ–‰์ด ์•„๋‹ˆ๋ผ ์—ด์„ ๋ฏผ๋‹ค. ๋ฐ”๊นฅ ๋ฃจํ”„๊ฐ€ i ๋ฅผ 0๋ถ€ํ„ฐ 4๊นŒ์ง€ ๋Œ๋ฆฌ๊ณ  ์•ˆ์ชฝ์—์„œ i ๋ฒˆ ๋ฐ˜๋ณตํ•˜๋‹ˆ, ์—ด i ๋Š” i ์นธ ์œ„๋กœ ๊ฐ„๋‹ค.

๋งˆ์ง€๋ง‰์œผ๋กœ ํ‘œ๋ฅผ ํ™•์ธํ•œ๋‹ค.

objdump -s -j .rodata --start-address=0x2020 --stop-address=0x2060 extracted/prob; objdump -s -j .data extracted/prob

objdump -s ๋กœ ๋ณธ rodata ์™€ data โ€” 0x2020 ์˜ 8d 01 02 04 08 10 20 40 80 1b 36 ์€ ํ‘œ์ค€ AES Rcon ์ด๊ณ  0x2040 ์€ ํ‘œ์ค€ AES S-box ๋‹ค. data ์—๋Š” ์ •๋‹ต ์•”ํ˜ธ๋ฌธ 25๋ฐ”์ดํŠธ์™€ ๋งˆ์Šคํ„ฐํ‚ค a_merry_christmas_for_you ๊ฐ€ ์žˆ๋‹ค
objdump -s ๋กœ ๋ณธ rodata ์™€ data โ€” 0x2020 ์˜ 8d 01 02 04 08 10 20 40 80 1b 36 ์€ ํ‘œ์ค€ AES Rcon ์ด๊ณ  0x2040 ์€ ํ‘œ์ค€ AES S-box ๋‹ค. data ์—๋Š” ์ •๋‹ต ์•”ํ˜ธ๋ฌธ 25๋ฐ”์ดํŠธ์™€ ๋งˆ์Šคํ„ฐํ‚ค a_merry_christmas_for_you ๊ฐ€ ์žˆ๋‹ค

  • 0x2020 : 8d 01 02 04 08 10 20 40 80 1b 36 โ€” ํ‘œ์ค€ AES Rcon ์ด๋‹ค. ์„ ๋‘์˜ 0x8d ๊นŒ์ง€ ๊ทธ๋Œ€๋กœ๋‹ค.
  • 0x2040 : 63 7c 77 7b f2 6b 6f c5 โ€ฆ โ€” ํ‘œ์ค€ AES S-box.
  • 0x4010 : ์ •๋‹ต ์•”ํ˜ธ๋ฌธ 25๋ฐ”์ดํŠธ 37a6b227โ€ฆe20e.
  • 0x4030 : a_merry_christmas_for_you โ€” 25๋ฐ”์ดํŠธ ๋งˆ์Šคํ„ฐํ‚ค.

ํ‘œ๋ฅผ ์ง์ ‘ ๋งŒ๋“ค์ง€ ์•Š๊ณ  ์ง„์งœ AES ๊ฒƒ์„ ๊ทธ๋Œ€๋กœ ๊ฐ€์ ธ๋‹ค ์“ด ์…ˆ์ด๋‹ค. ๊ทธ๋ž˜์„œ ๊ฒ‰๋ณด๊ธฐ์—” AES ์ธ๋ฐ, ์ •์ž‘ ํ™•์‚ฐ์„ ๋‹ด๋‹นํ•˜๋Š” ๋‹จ๊ณ„๋งŒ ๋น ์ ธ ์žˆ๋‹ค.



๐Ÿ’ฃ ํ•ต์‹ฌ โ€” MixColumns ๊ฐ€ ์—†์œผ๋ฉด ๋‚จ๋Š” ๊ฒŒ ์—†๋‹ค

MixColumns ๋ฅผ ๋นผ๋ฉด ๋ผ์šด๋“œ ํ•จ์ˆ˜๋Š” ์„ธ ์กฐ๊ฐ์ด ๋˜๋Š”๋ฐ, ์…‹ ๋‹ค ์ž๋ฆฌ ๋‹จ์œ„ ์—ฐ์‚ฐ์ด๋‹ค.

๋‹จ๊ณ„ํ•˜๋Š” ์ผ๋ฐ”์ดํŠธ๋ฅผ ์„ž๋Š”๊ฐ€
SubBytesst[x] = SBOX[st[x]]์•„๋‹ˆ์˜ค โ€” ์ž๋ฆฌ ์•ˆ์—์„œ ๊ฐ’๋งŒ ๋ฐ”๋€๋‹ค
ShiftCols์—ด j ๋ฅผ j ์นธ ์œ„๋กœ์•„๋‹ˆ์˜ค โ€” ๊ฐ’์€ ๊ทธ๋Œ€๋กœ ์ž๋ฆฌ๋งŒ ์˜ฎ๊ธด๋‹ค
AddRoundKeyst[x] ^= rk[25r + x]์•„๋‹ˆ์˜ค โ€” ๊ฐ™์€ ์ž๋ฆฌ๋ผ๋ฆฌ XOR

์„ธ ๊ฐœ๋ฅผ ์•„๋ฌด๋ฆฌ ๊ฒน์ณ ์Œ“์•„๋„ "ํ‰๋ฌธ ๋ฐ”์ดํŠธ ํ•˜๋‚˜ โ†’ ์•”ํ˜ธ๋ฌธ ๋ฐ”์ดํŠธ ํ•˜๋‚˜" ๋ผ๋Š” ๊ด€๊ณ„๊ฐ€ ์œ ์ง€๋œ๋‹ค. ๋ผ์šด๋“œ๋ฅผ ์—ด ๋ฒˆ ๋Œ๋ฆฌ๋ฉด ์ž๋ฆฌ๊ฐ€ ์—ฌ๊ธฐ์ €๊ธฐ ์˜ฎ๊ฒจ ๋‹ค๋‹ ๋ฟ, ์„œ๋กœ ์„ž์ด์ง€๋Š” ์•Š๋Š”๋‹ค.

๊ทธ๋Ÿฐ๋ฐ ์ด ๋ฌธ์ œ๋Š” ํ•œ ์ˆ  ๋” ๋œฌ๋‹ค. ์—ด ํšŒ์ „๋งˆ์ € ์ƒ์‡„๋œ๋‹ค.

์—ด j ๋Š” ๋ผ์šด๋“œ๋งˆ๋‹ค j ์นธ์”ฉ ์œ„๋กœ ๊ฐ„๋‹ค. ์—ด์˜ ๊ธธ์ด๊ฐ€ 5 ์ด๋ฏ€๋กœ 5๋ผ์šด๋“œ๊ฐ€ ์ง€๋‚˜๋ฉด 5j ์นธ, ์ฆ‰ ์ •ํ™•ํžˆ j ๋ฐ”ํ€ด๋ฅผ ๋Œ์•„ ์ œ์ž๋ฆฌ๋‹ค. ๋ผ์šด๋“œ๊ฐ€ 10 ์ด๋‹ˆ ๋‘ ๋ฐ”ํ€ด๋‹ค.

์ง์ ‘ ๊ทธ๋ฆฐ ๋„์‹ โ€” ์—ด 3 ์ด ๋ผ์šด๋“œ๋งˆ๋‹ค 3์นธ์”ฉ ์œ„๋กœ ๋ฐ€๋ฆฌ๋‹ค๊ฐ€ 5๋ผ์šด๋“œ ๋งŒ์— ์›๋ž˜ ๋ฐฐ์—ด๋กœ ๋Œ์•„์˜จ๋‹ค. ๋ผ์šด๋“œ๊ฐ€ 10 ์ด๋ผ ๋ชจ๋“  ์—ด์ด ๋‘ ๋ฐ”ํ€ด๋ฅผ ๋Œ์•„ ์ž๋ฆฌ ์ˆœ์—ด์ด ํ•ญ๋“ฑ์ด ๋œ๋‹ค
์ง์ ‘ ๊ทธ๋ฆฐ ๋„์‹ โ€” ์—ด 3 ์ด ๋ผ์šด๋“œ๋งˆ๋‹ค 3์นธ์”ฉ ์œ„๋กœ ๋ฐ€๋ฆฌ๋‹ค๊ฐ€ 5๋ผ์šด๋“œ ๋งŒ์— ์›๋ž˜ ๋ฐฐ์—ด๋กœ ๋Œ์•„์˜จ๋‹ค. ๋ผ์šด๋“œ๊ฐ€ 10 ์ด๋ผ ๋ชจ๋“  ์—ด์ด ๋‘ ๋ฐ”ํ€ด๋ฅผ ๋Œ์•„ ์ž๋ฆฌ ์ˆœ์—ด์ด ํ•ญ๋“ฑ์ด ๋œ๋‹ค

๋ง๋กœ๋งŒ ํ•˜๋ฉด ๋ฏธ๋ฅ์ง€ ์•Š์œผ๋‹ˆ ์ˆซ์ž๋กœ ํ™•์ธํ•œ๋‹ค. 1๋น„ํŠธ๋ฅผ ๋’ค์ง‘์—ˆ์„ ๋•Œ ์•”ํ˜ธ๋ฌธ ๋ฐ”์ดํŠธ๊ฐ€ ๋ช‡ ๊ฐœ๋‚˜ ๋ฐ”๋€Œ๋Š”์ง€ ์„ธ๊ณ , ์ž๋ฆฌ ๋Œ€์‘์ด ์‹ค์ œ๋กœ ์–ด๋–ป๊ฒŒ ๋˜๋Š”์ง€ ๋ฝ‘๊ณ , ๋งˆ์ง€๋ง‰์œผ๋กœ ํ‚ค๋ฅผ ์ „ํ˜€ ๋ชจ๋ฅธ๋‹ค๊ณ  ๊ฐ€์ •ํ–ˆ์„ ๋•Œ ์ฝ”๋“œ๋ถ์„ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋Š”์ง€๊นŒ์ง€ ํ•œ ๋ฒˆ์— ๋ณธ๋‹ค.

#!/usr/bin/env python3
"""์ด ๋ฌธ์ œ์˜ ๊ธ‰์†Œ๊ฐ€ 'MixColumns ์—†์Œ'์ด๋ผ๋Š” ๊ฒƒ์„ ์ˆ˜์น˜๋กœ ํ™•์ธํ•œ๋‹ค.
 
ํ™•์‚ฐ(diffusion)์ด ์—†์œผ๋ฉด ์•”ํ˜ธ๋ฌธ ๋ฐ”์ดํŠธ ํ•˜๋‚˜๊ฐ€ ํ‰๋ฌธ ๋ฐ”์ดํŠธ ํ•˜๋‚˜์—๋งŒ ์˜์กดํ•œ๋‹ค.
๊ทธ๋Ÿฌ๋ฉด ํ‚ค๋ฅผ ๋ชฐ๋ผ๋„ ์„ ํƒํ‰๋ฌธ 256๊ฐœ๋กœ ์ฝ”๋“œ๋ถ์„ ํ†ต์งธ๋กœ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋‹ค.
"""
from Crypto.Cipher import AES
import cipher
 
rk = cipher.key_expand()
BASE = bytes(range(25))
 
 
def flipped(pt, bit):
    b = bytearray(pt)
    b[bit // 8] ^= 1 << (bit % 8)
    return bytes(b)
 
 
print("=== 1. ๋ˆˆ์‚ฌํƒœ ํšจ๊ณผ (1๋น„ํŠธ ๋’ค์ง‘๊ณ  ๋ฐ”๋€ ๋ฐ”์ดํŠธ ์ˆ˜) ===")
c0 = cipher.encrypt(BASE, rk)
worst = 0
for bit in range(25 * 8):
    c1 = cipher.encrypt(flipped(BASE, bit), rk)
    n = sum(x != y for x, y in zip(c0, c1))
    worst = max(worst, n)
print(f"locked present : 200๋น„ํŠธ ์ „๋ถ€ ์‹œํ—˜ -> ๋ฐ”๋€ ๋ฐ”์ดํŠธ ์ตœ๋Œ€ {worst} / 25")
 
aes = AES.new(b"a_merry_christma", AES.MODE_ECB)   # ๋น„๊ต์šฉ ์ง„์งœ AES-128
p0 = bytes(range(16))
a0 = aes.encrypt(p0)
aworst, abest = 0, 16
for bit in range(16 * 8):
    b = bytearray(p0)
    b[bit // 8] ^= 1 << (bit % 8)
    n = sum(x != y for x, y in zip(a0, aes.encrypt(bytes(b))))
    aworst, abest = max(aworst, n), min(abest, n)
print(f"์ง„์งœ AES-128   : 128๋น„ํŠธ ์ „๋ถ€ ์‹œํ—˜ -> ๋ฐ”๋€ ๋ฐ”์ดํŠธ {abest}~{aworst} / 16")
 
print()
print("=== 2. ํ‰๋ฌธ ์ž๋ฆฌ -> ์•”ํ˜ธ๋ฌธ ์ž๋ฆฌ ์ˆœ์—ด ===")
perm = {}
for i in range(25):
    b = bytearray(BASE)
    b[i] ^= 0xFF
    diff = [j for j in range(25) if cipher.encrypt(bytes(b), rk)[j] != c0[j]]
    assert len(diff) == 1, f"์ž๋ฆฌ {i} ๊ฐ€ {len(diff)}๊ณณ์— ๋ฒˆ์กŒ๋‹ค"
    perm[i] = diff[0]
print("  ํ‰๋ฌธ idx -> ์•”ํ˜ธ๋ฌธ idx :", ", ".join(f"{i}->{perm[i]}" for i in range(25)))
 
print()
print("=== 3. ํ‚ค ์—†์ด ์ฝ”๋“œ๋ถ ๋ณต๊ตฌ (์„ ํƒํ‰๋ฌธ 256๊ฐœ) ===")
# ์ž๋ฆฌ๋งˆ๋‹ค 'ํ‰๋ฌธ ๋ฐ”์ดํŠธ v -> ์•”ํ˜ธ๋ฌธ ๋ฐ”์ดํŠธ' ํ‘œ๋ฅผ ํ†ต์งธ๋กœ ๋งŒ๋“ ๋‹ค.
table = [dict() for _ in range(25)]
for v in range(256):
    ct = cipher.encrypt(bytes([v]) * 25, rk)
    for i in range(25):
        table[i][ct[perm[i]]] = v
flag = bytes(table[i][cipher.CIPHER[perm[i]]] for i in range(25))
print(f"  ์งˆ์˜ 256ํšŒ๋กœ ๋ณต์›ํ•œ ํ‰๋ฌธ: {flag!r}")
assert flag == cipher.decrypt(cipher.CIPHER, rk)
print("  -> .data ์˜ ๋งˆ์Šคํ„ฐํ‚ค๋ฅผ ํ•œ ๋ฒˆ๋„ ์ฝ์ง€ ์•Š๊ณ  ๊ฐ™์€ ๊ฐ’์ด ๋‚˜์˜จ๋‹ค")
python3 diffusion.py

diffusion.py ์‹คํ–‰ ๊ฒฐ๊ณผ โ€” locked present ๋Š” 1๋น„ํŠธ๋ฅผ ๋’ค์ง‘์–ด๋„ ๋ฐ”๋€Œ๋Š” ์•”ํ˜ธ๋ฌธ ๋ฐ”์ดํŠธ๊ฐ€ ์ตœ๋Œ€ 1๊ฐœ์ธ๋ฐ ์ง„์งœ AES-128 ์€ 15~16๊ฐœ๊ฐ€ ๋ฐ”๋€๋‹ค. ์ž๋ฆฌ ๋Œ€์‘์€ 0์—์„œ 24๊นŒ์ง€ ์ „๋ถ€ ํ•ญ๋“ฑ์ด๊ณ  ์„ ํƒํ‰๋ฌธ 256๊ฐœ๋กœ ํ‰๋ฌธ ์ „์ฒด๊ฐ€ ๋ณต๊ตฌ๋œ๋‹ค
diffusion.py ์‹คํ–‰ ๊ฒฐ๊ณผ โ€” locked present ๋Š” 1๋น„ํŠธ๋ฅผ ๋’ค์ง‘์–ด๋„ ๋ฐ”๋€Œ๋Š” ์•”ํ˜ธ๋ฌธ ๋ฐ”์ดํŠธ๊ฐ€ ์ตœ๋Œ€ 1๊ฐœ์ธ๋ฐ ์ง„์งœ AES-128 ์€ 15~16๊ฐœ๊ฐ€ ๋ฐ”๋€๋‹ค. ์ž๋ฆฌ ๋Œ€์‘์€ 0์—์„œ 24๊นŒ์ง€ ์ „๋ถ€ ํ•ญ๋“ฑ์ด๊ณ  ์„ ํƒํ‰๋ฌธ 256๊ฐœ๋กœ ํ‰๋ฌธ ์ „์ฒด๊ฐ€ ๋ณต๊ตฌ๋œ๋‹ค

์„ธ ์ค„ ๋‹ค ์˜ˆ์ƒ๋Œ€๋กœ๋‹ค.

  • ๋ˆˆ์‚ฌํƒœ ํšจ๊ณผ: 200๋น„ํŠธ๋ฅผ ์ „๋ถ€ ๋’ค์ง‘์–ด ๋ด๋„ ๋ฐ”๋€Œ๋Š” ์•”ํ˜ธ๋ฌธ ๋ฐ”์ดํŠธ๋Š” ์ตœ๋Œ€ 1๊ฐœ. ๋น„๊ต์šฉ์œผ๋กœ ๊ฐ™์ด ๋Œ๋ฆฐ ์ง„์งœ AES-128 ์€ 128๋น„ํŠธ ์–ด๋А ๊ฒƒ์„ ๋’ค์ง‘์–ด๋„ 16๋ฐ”์ดํŠธ ์ค‘ 15~16๊ฐœ๊ฐ€ ๋ฐ”๋€๋‹ค.
  • ์ž๋ฆฌ ์ˆœ์—ด: 0โ†’0, 1โ†’1, โ€ฆ 24โ†’24. ์˜ˆ์ƒ๋Œ€๋กœ ํ•ญ๋“ฑ์ด๋‹ค.
  • ์ฝ”๋“œ๋ถ: ์ž๋ฆฌ๋งˆ๋‹ค "ํ‰๋ฌธ ๋ฐ”์ดํŠธ โ†’ ์•”ํ˜ธ๋ฌธ ๋ฐ”์ดํŠธ" ํ‘œ๊ฐ€ ๋…๋ฆฝ์ด๋ฏ€๋กœ, ๊ฐ™์€ ๋ฐ”์ดํŠธ๋กœ ์ฑ„์šด ํ‰๋ฌธ 256๊ฐœ๋งŒ ๋„ฃ์–ด ๋ณด๋ฉด ํ‘œ 25๊ฐœ๊ฐ€ ํ†ต์งธ๋กœ ์™„์„ฑ๋œ๋‹ค. ์•ž ๋‹จ๊ณ„์—์„œ ์ž๋ฆฌ ๋Œ€์‘์„ ํ™•์ธํ•˜๋Š” ๋ฐ ์“ด 25ํšŒ๊นŒ์ง€ ์„ธ๋ฉด 281ํšŒ๋‹ค. .data ์˜ ๋งˆ์Šคํ„ฐํ‚ค๋ฅผ ํ•œ ๋ฒˆ๋„ ์ฝ์ง€ ์•Š๊ณ  ๊ฐ™์€ ํ‰๋ฌธ์ด ๋‚˜์˜จ๋‹ค.

๋งˆ์ง€๋ง‰ ํ•ญ๋ชฉ์ด ์ด ์„ค๊ณ„์˜ ์ง„์งœ ๋ฌธ์ œ๋‹ค. ํ‚ค๋ฅผ ์ˆจ๊ฒจ ๋ด์•ผ ์†Œ์šฉ์ด ์—†๋‹ค. ์•”ํ˜ธํ™” ์˜ค๋ผํด๋งŒ ์žˆ์œผ๋ฉด 300ํšŒ ๋‚จ์ง“ํ•œ ์งˆ์˜๋กœ ์‚ฌ์ „์ด ๋‹ค ํ„ธ๋ฆฐ๋‹ค.



๐ŸŽฏ ํ’€์ด โ€” ๋˜๊ฐ๊ธฐ

๊ตฌ์กฐ๋ฅผ ์•Œ์•˜์œผ๋‹ˆ ๋˜๊ฐ์œผ๋ฉด ๋œ๋‹ค. ๋จผ์ € ๋ฐ”์ด๋„ˆ๋ฆฌ์˜ ๋ฃจํ‹ด์„ ๊ทธ๋Œ€๋กœ ์˜ฎ๊ธด๋‹ค. S-boxยทRconยท์•”ํ˜ธ๋ฌธยทํ‚ค๋Š” ํ•˜๋“œ์ฝ”๋”ฉํ•˜์ง€ ์•Š๊ณ  ELF ์—์„œ ์ง์ ‘ ์ฝ๊ฒŒ ํ–ˆ๋‹ค โ€” ์˜ฎ๊ฒจ ์ ๋‹ค ํ‹€๋ฆฌ๋Š” ๊ฑธ ๋ง‰๊ณ , ๋‚˜์ค‘์— ๋ˆ„๊ฐ€ ๋‹ค์‹œ ๋Œ๋ ค๋„ ๊ฐ™์€ ๊ฐ’์ด ๋‚˜์˜จ๋‹ค.

#!/usr/bin/env python3
"""locked present (DreamHack, Silver 1) - prob ๋ฐ”์ด๋„ˆ๋ฆฌ์˜ ์•”ํ˜ธ ๋ฃจํ‹ด์„ ๊ทธ๋Œ€๋กœ ์žฌ๊ตฌํ˜„ํ•œ๋‹ค.
 
์ƒ์ˆ˜(S-box / Rcon / ์•”ํ˜ธ๋ฌธ / ๋งˆ์Šคํ„ฐํ‚ค)๋Š” ํ•˜๋“œ์ฝ”๋”ฉํ•˜์ง€ ์•Š๊ณ  ELF ์—์„œ ์ง์ ‘ ์ฝ๋Š”๋‹ค.
๋ฐ”์ด๋„ˆ๋ฆฌ๋Š” PIE ๋ผ objdump ๊ฐ€ ๋ณด์—ฌ ์ฃผ๋Š” 0x2040 ๊ฐ™์€ ์ฃผ์†Œ๊ฐ€ ๊ณง ํŒŒ์ผ ์˜คํ”„์…‹์ด๋‹ค
(.rodata: vaddr 0x2000 == file offset 0x2000, .data: vaddr 0x4000 == file offset 0x3000).
"""
import struct
from pathlib import Path
 
BIN = Path(__file__).resolve().parent / "extracted" / "prob"
 
 
def read_sections(path):
    """ELF ์„น์…˜ ํ—ค๋”๋ฅผ ์ง์ ‘ ํŒŒ์‹ฑํ•ด vaddr -> file offset ๋ณ€ํ™˜ํ‘œ๋ฅผ ๋งŒ๋“ ๋‹ค."""
    blob = path.read_bytes()
    e_shoff, = struct.unpack_from("<Q", blob, 0x28)
    e_shentsize, = struct.unpack_from("<H", blob, 0x3A)
    e_shnum, = struct.unpack_from("<H", blob, 0x3C)
    e_shstrndx, = struct.unpack_from("<H", blob, 0x3E)
 
    def sh(i):
        off = e_shoff + i * e_shentsize
        name, _typ, _flags, addr, offset, size = struct.unpack_from("<IIQQQQ", blob, off)
        return name, addr, offset, size
 
    _, _, stroff, _ = sh(e_shstrndx)
    out = {}
    for i in range(e_shnum):
        name, addr, offset, size = sh(i)
        end = blob.index(b"\0", stroff + name)
        out[blob[stroff + name:end].decode()] = (addr, offset, size)
    return blob, out
 
 
BLOB, SECTIONS = read_sections(BIN)
 
 
def at(vaddr, n):
    """๊ฐ€์ƒ์ฃผ์†Œ vaddr ์—์„œ n ๋ฐ”์ดํŠธ๋ฅผ ์ฝ๋Š”๋‹ค."""
    for _name, (addr, offset, size) in SECTIONS.items():
        if addr and addr <= vaddr < addr + size:
            delta = vaddr - addr
            return BLOB[offset + delta:offset + delta + n]
    raise ValueError(f"0x{vaddr:x} ๋ฅผ ๋‹ด์€ ์„น์…˜์ด ์—†๋‹ค")
 
 
SBOX = at(0x2040, 256)          # 0x1572 sub_bytes ๊ฐ€ ์ฐธ์กฐ
RCON = at(0x2020, 16)           # 0x1336 key_expand ๊ฐ€ ์ฐธ์กฐ
CIPHER = at(0x4010, 25)         # main 0x18b3 ์ด ๋น„๊ตํ•˜๋Š” ์ •๋‹ต
KEY = at(0x4030, 25)            # main 0x1831 ์ด key_expand ๋กœ ๋„˜๊ธฐ๋Š” ๋งˆ์Šคํ„ฐํ‚ค
INV_SBOX = bytes(SBOX.index(i) for i in range(256))
 
NR = 10                         # encrypt 0x174d: ๋ผ์šด๋“œ 1..10
BS = 25                         # 5x5 ์ƒํƒœ
 
 
def key_expand(key=KEY):
    """0x1254 ๋ฅผ ๊ทธ๋Œ€๋กœ ์˜ฎ๊ธด ๊ฒƒ. ๋ผ์šด๋“œํ‚ค 11๊ฐœ(25*11=275=malloc(0x113)) ๋ฅผ ๋งŒ๋“ ๋‹ค."""
    rk = bytearray(25 * (NR + 1))
    rk[0:25] = key[0:25]
    temp = bytearray(rk[15:20])          # 0x12ac: rk[i+0xf] โ€” ๋งˆ์ง€๋ง‰ ํ–‰(20..24)์ด ์•„๋‹ˆ๋ผ ํ–‰ 3์ด๋‹ค
    for n in range(1, NR + 1):
        temp = temp[1:] + temp[:1]       # 0x11e9 rot5: ์ขŒํšŒ์ „ 1
        for k in range(5):               # 0x12f0 ๋ฃจํ”„
            rk[25 * n + k] = rk[25 * (n - 1) + k] ^ SBOX[temp[k]] ^ RCON[n]
        for i in range(1, 5):            # 0x138e ๋ฃจํ”„
            for j in range(5):
                rk[25 * n + 5 * i + j] = (rk[25 * n + 5 * (i - 1) + j]
                                          ^ rk[25 * (n - 1) + 5 * i + j])
                temp[j] = rk[25 * n + 5 * i + j]
    return bytes(rk)
 
 
def add_round_key(st, rk, r):
    """0x14a7. state[5i+j] ^= rk[25r + 5i + j]"""
    for x in range(BS):
        st[x] ^= rk[25 * r + x]
 
 
def sub_bytes(st):
    """0x1572. 25๋ฐ”์ดํŠธ ์ „๋ถ€ S-box ์น˜ํ™˜"""
    for x in range(BS):
        st[x] = SBOX[st[x]]
 
 
def inv_sub_bytes(st):
    for x in range(BS):
        st[x] = INV_SBOX[st[x]]
 
 
def shift_cols(st):
    """0x15fb. ์—ด i(=์ธ๋ฑ์Šค i, i+5, i+10, i+15, i+20)๋ฅผ i ๋ฒˆ '์œ„๋กœ' ํšŒ์ „."""
    for i in range(5):
        col = [st[5 * k + i] for k in range(5)]
        col = col[i:] + col[:i]
        for k in range(5):
            st[5 * k + i] = col[k]
 
 
def inv_shift_cols(st):
    for i in range(5):
        col = [st[5 * k + i] for k in range(5)]
        col = col[-i:] + col[:-i] if i else col
        for k in range(5):
            st[5 * k + i] = col[k]
 
 
def encrypt(pt, rk):
    """0x16e2. ARK(0) ๋‹ค์Œ r=1..10 ์œผ๋กœ SubBytes -> ShiftCols -> ARK."""
    st = bytearray(pt)
    add_round_key(st, rk, 0)
    for r in range(1, NR + 1):
        sub_bytes(st)
        shift_cols(st)
        add_round_key(st, rk, r)
    return bytes(st)
 
 
def decrypt(ct, rk):
    """encrypt ๋ฅผ ์—ญ์ˆœ์œผ๋กœ ๋˜๊ฐ๋Š”๋‹ค. MixColumns ๊ฐ€ ์—†์–ด ๊ฐ ๋‹จ๊ณ„๊ฐ€ ์ „๋ถ€ ๋ฐ”์ดํŠธ ๋‹จ์œ„๋กœ ๊ฐ€์—ญ."""
    st = bytearray(ct)
    for r in range(NR, 0, -1):
        add_round_key(st, rk, r)
        inv_shift_cols(st)
        inv_sub_bytes(st)
    add_round_key(st, rk, 0)
    return bytes(st)

ํ‚ค ํ™•์žฅ์—์„œ ์ง„์งœ AES ์™€ ๋‹ค๋ฅธ ์ง€์ ์ด ๋‘˜ ์žˆ๋Š”๋ฐ, ๋‘˜ ๋‹ค objdump ๋ฅผ ํ•œ ์ค„์”ฉ ๋”ฐ๋ผ๊ฐ€์•ผ ๋ณด์ธ๋‹ค.

  • ์ดˆ๊ธฐ temp ๋ฅผ rk[20:25](๋งˆ์ง€๋ง‰ ์›Œ๋“œ)๊ฐ€ ์•„๋‹ˆ๋ผ rk[15:20] ์—์„œ ๊ฐ€์ ธ์˜จ๋‹ค. 0x12af ์˜ add eax,0xf ๊ฐ€ ๊ทธ๊ฒƒ์ด๋‹ค.
  • Rcon ์„ ์ฒซ ๋ฐ”์ดํŠธ์—๋งŒ XOR ํ•˜์ง€ ์•Š๊ณ  5๋ฐ”์ดํŠธ ์ „๋ถ€์— XOR ํ•œ๋‹ค. 0x12f0 ๋ฃจํ”„๊ฐ€ k ์™€ ๋ฌด๊ด€ํ•˜๊ฒŒ RCON[n] ์„ ์„ž๋Š”๋‹ค.

๋ณตํ˜ธ๋Š” ๋ผ์šด๋“œ๋ฅผ ์—ญ์ˆœ์œผ๋กœ ๋˜๊ฐ๋Š” ๊ฒƒ๋ฟ์ด๋‹ค.

#!/usr/bin/env python3
"""locked present โ€” ์ •๋‹ต ์•”ํ˜ธ๋ฌธ์„ ๋ณตํ˜ธํ•ด ๋น„๋ฐ€๋ฒˆํ˜ธ๋ฅผ ๋ฝ‘๋Š”๋‹ค.
 
MixColumns ๊ฐ€ ์—†์œผ๋ฏ€๋กœ SubBytes(๋ฐ”์ดํŠธ ๋‹จ์œ„ ์ „๋‹จ์‚ฌ) / ShiftCols(์ž๋ฆฌ ์ˆœ์—ด) /
AddRoundKey(XOR) ์…‹ ๋‹ค ๊ฐœ๋ณ„์ ์œผ๋กœ ๋˜๊ฐ์„ ์ˆ˜ ์žˆ๋‹ค. ํ‚ค๊ฐ€ .data ์— ๋ฐ•ํ˜€ ์žˆ์œผ๋‹ˆ
๋ผ์šด๋“œํ‚ค๋ฅผ ๊ทธ๋Œ€๋กœ ๋งŒ๋“ค์–ด 10๋ผ์šด๋“œ๋ฅผ ์—ญ์ˆœ์œผ๋กœ ํ’€๋ฉด ๋์ด๋‹ค.
"""
import cipher
 
rk = cipher.key_expand()
pt = cipher.decrypt(cipher.CIPHER, rk)
 
print(f"[*] ๋ผ์šด๋“œํ‚ค {len(rk)}๋ฐ”์ดํŠธ = 25 x {cipher.NR + 1}")
print(f"[*] ์•”ํ˜ธ๋ฌธ  : {cipher.CIPHER.hex()}")
print(f"[*] ๋ณตํ˜ธ๊ฒฐ๊ณผ: {pt!r}")
 
# ๋˜๊ฐ์€ ๊ฐ’์„ ๋‹ค์‹œ ์•”ํ˜ธํ™”ํ•ด์„œ .data ์˜ ์ •๋‹ต๊ณผ ์™„์ „ํžˆ ๊ฐ™์€์ง€ ํ™•์ธํ•œ๋‹ค.
back = cipher.encrypt(pt, rk)
assert back == cipher.CIPHER, "์žฌ์•”ํ˜ธํ™” ๋ถˆ์ผ์น˜ โ€” ๊ตฌํ˜„์ด ํ‹€๋ ธ๋‹ค"
print(f"[+] ์žฌ์•”ํ˜ธํ™” ๊ฒ€์ฆ: {back.hex()} == .data@0x4010  OK")
 
print()
print(f"password = {pt.decode()}")
python3 solve.py

solve.py ์‹คํ–‰ ๊ฒฐ๊ณผ โ€” ๋ผ์šด๋“œํ‚ค 275๋ฐ”์ดํŠธ๋ฅผ ๋งŒ๋“ค์–ด ์•”ํ˜ธ๋ฌธ์„ ๋˜๊ฐ์œผ๋‹ˆ 25๋ฐ”์ดํŠธ ๋น„๋ฐ€๋ฒˆํ˜ธ๊ฐ€ ๋‚˜์˜ค๊ณ  ๊ทธ๊ฑธ ๋‹ค์‹œ ์•”ํ˜ธํ™”ํ•œ ๊ฐ’์ด data 0x4010 ์˜ ์ •๋‹ต ์•”ํ˜ธ๋ฌธ๊ณผ ์™„์ „ํžˆ ์ผ์น˜ํ•œ๋‹ค
solve.py ์‹คํ–‰ ๊ฒฐ๊ณผ โ€” ๋ผ์šด๋“œํ‚ค 275๋ฐ”์ดํŠธ๋ฅผ ๋งŒ๋“ค์–ด ์•”ํ˜ธ๋ฌธ์„ ๋˜๊ฐ์œผ๋‹ˆ 25๋ฐ”์ดํŠธ ๋น„๋ฐ€๋ฒˆํ˜ธ๊ฐ€ ๋‚˜์˜ค๊ณ  ๊ทธ๊ฑธ ๋‹ค์‹œ ์•”ํ˜ธํ™”ํ•œ ๊ฐ’์ด data 0x4010 ์˜ ์ •๋‹ต ์•”ํ˜ธ๋ฌธ๊ณผ ์™„์ „ํžˆ ์ผ์น˜ํ•œ๋‹ค

DH{W0w_U_kn0w_4b0ut_AES?} โ€” ์ •ํ™•ํžˆ 25๋ฐ”์ดํŠธ๋‹ค. ๋ธ”๋ก ํ•˜๋‚˜์— ๋”ฑ ๋งž์œผ๋‹ˆ ํŒจ๋”ฉ ๊ณ ๋ฏผ๋„ ์—†์—ˆ๋˜ ๊ฒƒ์ด๋‹ค.



๐Ÿ› ์‚ฝ์งˆ โ€” ์กฐ์šฉํžˆ ํ‹€๋ฆฌ๋Š” ์˜ค๋… ๋„ค ๊ฐ€์ง€

์ด ๋ฌธ์ œ๋Š” ํ‹€๋ ค๋„ ์˜ˆ์™ธ๊ฐ€ ์•ˆ ๋‚œ๋‹ค. ์–ด๋–ป๊ฒŒ ์ž˜๋ชป ์ฝ๋“  25๋ฐ”์ดํŠธ์งœ๋ฆฌ ๊ทธ๋Ÿด๋“ฏํ•œ ๋ฐ”์ดํŠธ์—ด์ด ๋‚˜์˜ค๊ณ , ๊ทธ๊ฒŒ ๋‹ต์ด ์•„๋‹ ๋ฟ์ด๋‹ค. ์‹ค์ œ๋กœ ํ—ค๋งจ ์ง€์ ๋“ค์„ ๊ทธ๋Œ€๋กœ ์žฌํ˜„ํ•ด ๋ดค๋‹ค.

#!/usr/bin/env python3
"""์ด ๋ฌธ์ œ์—์„œ '์กฐ์šฉํžˆ ํ‹€๋ฆฌ๋Š”' ์˜ค๋… 4์ข…์„ ์‹ค์ œ๋กœ ๋Œ๋ ค ๋ณธ๋‹ค.
 
๋„ท ๋‹ค ์˜ˆ์™ธ๊ฐ€ ์•ˆ ๋‚œ๋‹ค. 25๋ฐ”์ดํŠธ์งœ๋ฆฌ ๊ทธ๋Ÿด๋“ฏํ•œ ๋ฐ”์ดํŠธ์—ด์ด ๋‚˜์˜ค๊ณ , ๊ทธ๊ฒŒ flag ๊ฐ€ ์•„๋‹ ๋ฟ์ด๋‹ค.
์ฆ‰ ๋ˆˆ์œผ๋กœ๋Š” ๋ชป ์žก๊ณ  '์žฌ์•”ํ˜ธํ™”ํ•ด์„œ .data ์™€ ๋Œ€์กฐ' ํ•˜๋Š” ๊ฒ€์ฆ๋งŒ์ด ํŒ๋ณ„๊ธฐ๋‹ค.
"""
import cipher
 
REAL = b"DH{W0w_U_kn0w_4b0ut_AES?}"
 
 
def report(name, pt):
    printable = all(0x20 <= b < 0x7F for b in pt)
    verdict = "์ •๋‹ต" if pt == REAL else "์˜ค๋‹ต"
    print(f"  [{verdict}] {name}")
    print(f"          -> {pt!r}")
    print(f"          ์ถœ๋ ฅ๊ฐ€๋Šฅ๋ฌธ์ž๋งŒ์ธ๊ฐ€: {printable} / ์˜ˆ์™ธ ๋ฐœ์ƒ: ์—†์Œ")
 
 
def expand(temp_src=slice(15, 20), rcon_all=True):
    rk = bytearray(25 * 11)
    rk[0:25] = cipher.KEY
    temp = bytearray(rk[temp_src])
    for n in range(1, 11):
        temp = temp[1:] + temp[:1]
        for k in range(5):
            v = rk[25 * (n - 1) + k] ^ cipher.SBOX[temp[k]]
            if rcon_all or k == 0:
                v ^= cipher.RCON[n]
            rk[25 * n + k] = v
        for i in range(1, 5):
            for j in range(5):
                rk[25 * n + 5 * i + j] = (rk[25 * n + 5 * (i - 1) + j]
                                          ^ rk[25 * (n - 1) + 5 * i + j])
                temp[j] = rk[25 * n + 5 * i + j]
    return bytes(rk)
 
 
def dec(rk, inv_shift):
    st = bytearray(cipher.CIPHER)
    for r in range(10, 0, -1):
        cipher.add_round_key(st, rk, r)
        inv_shift(st)
        cipher.inv_sub_bytes(st)
    cipher.add_round_key(st, rk, 0)
    return bytes(st)
 
 
def inv_cols_down(st):       # ์ •๋‹ต: ์•”ํ˜ธํ™”๊ฐ€ '์œ„๋กœ' ๋Œ๋ ธ์œผ๋‹ˆ ๋ณตํ˜ธ๋Š” '์•„๋ž˜๋กœ'
    cipher.inv_shift_cols(st)
 
 
def inv_cols_up(st):         # ํ•จ์ • 3: ๋ฐฉํ–ฅ์„ ๋ฐ˜๋Œ€๋กœ
    cipher.shift_cols(st)
 
 
def inv_rows(st):            # ํ•จ์ • 4: ์—ด์ด ์•„๋‹ˆ๋ผ 'ํ–‰'์„ ๋Œ๋ฆฐ๋‹ค๊ณ  ์ฝ์Œ (์ง„์งœ AES ์˜ ShiftRows)
    for i in range(5):
        row = [st[5 * i + k] for k in range(5)]
        row = row[-i:] + row[:-i] if i else row
        for k in range(5):
            st[5 * i + k] = row[k]
 
 
print("์ •๋‹ต ๊ตฌํ˜„")
report("temp=rk[15:20] ยท Rcon 5๋ฐ”์ดํŠธ ์ „๋ถ€ ยท ์—ด์„ ์•„๋ž˜๋กœ", dec(expand(), inv_cols_down))
 
print("\nํ•จ์ • 1 โ€” ์ง„์งœ AES ์ฒ˜๋Ÿผ '๋งˆ์ง€๋ง‰ ์›Œ๋“œ'(rk[20:25])๋กœ ์‹œ์ž‘ํ•œ๋‹ค๊ณ  ์ฝ์Œ")
report("temp=rk[20:25]", dec(expand(temp_src=slice(20, 25)), inv_cols_down))
 
print("\nํ•จ์ • 2 โ€” ์ง„์งœ AES ์ฒ˜๋Ÿผ Rcon ์„ ์ฒซ ๋ฐ”์ดํŠธ์—๋งŒ XOR")
report("Rcon on k==0 only", dec(expand(rcon_all=False), inv_cols_down))
 
print("\nํ•จ์ • 3 โ€” ShiftCols ์—ญ๋ฐฉํ–ฅ (10๋ผ์šด๋“œ๊ฐ€ ์ƒ์‡„๋˜๋‹ˆ ๋ฐฉํ–ฅ์€ ์ƒ๊ด€์—†๋‹ค๊ณ  ์ฐฉ๊ฐ)")
report("์—ด์„ ์œ„๋กœ ๋˜๋Œ๋ฆผ", dec(expand(), inv_cols_up))
 
print("\nํ•จ์ • 4 โ€” ์—ด์ด ์•„๋‹ˆ๋ผ ํ–‰์„ ๋Œ๋ฆฐ๋‹ค๊ณ  ์ฝ์Œ (AES ์˜ ShiftRows ๋กœ ์˜ค๋…)")
report("ํ–‰ ํšŒ์ „", dec(expand(), inv_rows))
 
print("\n์ฐธ๊ณ  โ€” ๋ธ”๋ก์ด 25๋ฐ”์ดํŠธ๋ผ ์ง„์งœ AES ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋Š” ์• ์ดˆ์— ๋ชป ์“ด๋‹ค")
try:
    from Crypto.Cipher import AES
    AES.new(cipher.KEY, AES.MODE_ECB)
except ValueError as e:
    print(f"  Crypto.Cipher.AES.new(25๋ฐ”์ดํŠธ ํ‚ค) -> ValueError: {e}")
python3 traps.py

traps.py ์‹คํ–‰ ๊ฒฐ๊ณผ โ€” ์ •๋‹ต ๊ตฌํ˜„๋งŒ DH ๋กœ ์‹œ์ž‘ํ•˜๋Š” ๋ฌธ์ž์—ด์ด ๋‚˜์˜ค๊ณ  ๋‚˜๋จธ์ง€ ๋„ค ๊ฐ€์ง€ ์˜ค๋…์€ ์ „๋ถ€ ์˜ˆ์™ธ ์—†์ด ์ถœ๋ ฅ ๋ถˆ๊ฐ€๋Šฅํ•œ 25๋ฐ”์ดํŠธ๋ฅผ ๋‚ธ๋‹ค. 25๋ฐ”์ดํŠธ ํ‚ค๋ผ์„œ ์ง„์งœ AES ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋Š” ValueError ๋กœ ๊ฑฐ๋ถ€ํ•œ๋‹ค
traps.py ์‹คํ–‰ ๊ฒฐ๊ณผ โ€” ์ •๋‹ต ๊ตฌํ˜„๋งŒ DH ๋กœ ์‹œ์ž‘ํ•˜๋Š” ๋ฌธ์ž์—ด์ด ๋‚˜์˜ค๊ณ  ๋‚˜๋จธ์ง€ ๋„ค ๊ฐ€์ง€ ์˜ค๋…์€ ์ „๋ถ€ ์˜ˆ์™ธ ์—†์ด ์ถœ๋ ฅ ๋ถˆ๊ฐ€๋Šฅํ•œ 25๋ฐ”์ดํŠธ๋ฅผ ๋‚ธ๋‹ค. 25๋ฐ”์ดํŠธ ํ‚ค๋ผ์„œ ์ง„์งœ AES ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋Š” ValueError ๋กœ ๊ฑฐ๋ถ€ํ•œ๋‹ค

โ–ถ๐Ÿ› ์‚ฝ์งˆ 1 โ€” ์ง„์งœ AES ์ฒ˜๋Ÿผ '๋งˆ์ง€๋ง‰ ์›Œ๋“œ'๋กœ ์‹œ์ž‘ํ•œ๋‹ค๊ณ  ์ฝ์—ˆ๋‹ค

AES-128 ํ‚ค ํ™•์žฅ์€ W[4] = W[0] ^ g(W[3]) ์ฒ˜๋Ÿผ ์ง์ „ ์›Œ๋“œ๋ฅผ ๋ฌผ๊ณ  ์‹œ์ž‘ํ•œ๋‹ค. 25๋ฐ”์ดํŠธ ํ‚ค๋ฅผ 5์›Œ๋“œ๋กœ ๋ณด๋ฉด ๋งˆ์ง€๋ง‰ ์›Œ๋“œ๋Š” rk[20:25] ์—ฌ์•ผ ์ž์—ฐ์Šค๋Ÿฝ๋‹ค.

๊ทธ๋Ÿฐ๋ฐ ์ด ๋ฐ”์ด๋„ˆ๋ฆฌ๋Š” rk[15:20] ์„ ๊ฐ€์ ธ์˜จ๋‹ค. ๋ผ์šด๋“œ ๋ฃจํ”„ ๋์—์„œ temp ๋ฅผ ๊ฐฑ์‹ ํ•  ๋•Œ๋Š” ๋งˆ์ง€๋ง‰ ํ–‰(i=4)์„ ์“ฐ๋ฉด์„œ, ์ตœ์ดˆ ํ•œ ๋ฒˆ๋งŒ ํ–‰ 3 ์„ ์“ด๋‹ค. ์ถœ์ œ์ž์˜ ์‹ค์ˆ˜์ธ์ง€ ์˜๋„์ธ์ง€๋Š” ์•Œ ์ˆ˜ ์—†์ง€๋งŒ ๊ทธ๋Œ€๋กœ ์˜ฎ๊ฒจ์•ผ ๋งž๋Š”๋‹ค.

0x12ac ์˜ ์„ธ ์ค„์ด ๊ทผ๊ฑฐ๋‹ค. add eax,0xf ์˜ 0xf = 15.

12ac:   mov    eax,DWORD PTR [rbp-0x1c]   ; i
12af:   add    eax,0xf                    ; i + 15  <- 20 ์ด ์•„๋‹ˆ๋‹ค
12b2:   mov    edx,eax

์ด๊ฑธ 20 ์œผ๋กœ ์ฝ์œผ๋ฉด ๋ผ์šด๋“œํ‚ค ์—ด ๊ฐœ๊ฐ€ ์ „๋ถ€ ์–ด๊ธ‹๋‚˜๋Š”๋ฐ, ๋ณตํ˜ธ๋Š” ๋ฉ€์ฉกํžˆ ๋๋‚˜๊ณ  b'\xb7\x06\x82Lโ€ฆ' ์ด ๋‚˜์˜จ๋‹ค. ๊ธธ์ด๋„ 25 ๋ฐ”์ดํŠธ๋‹ค.

โ–ถ๐Ÿ› ์‚ฝ์งˆ 2 โ€” Rcon ์„ ์ฒซ ๋ฐ”์ดํŠธ์—๋งŒ XOR ํ–ˆ๋‹ค

AES ์˜ Rcon ์€ ์›Œ๋“œ์˜ ์ตœ์ƒ์œ„ ๋ฐ”์ดํŠธ ํ•˜๋‚˜์—๋งŒ ๋“ค์–ด๊ฐ„๋‹ค. ์Šต๊ด€๋Œ€๋กœ if k == 0 ์„ ๋ถ™์˜€๋”๋‹ˆ ์—ญ์‹œ ์กฐ์šฉํžˆ ํ‹€๋ ธ๋‹ค.

๋ฐ”์ด๋„ˆ๋ฆฌ๋Š” k ๋ฅผ 0๋ถ€ํ„ฐ 4๊นŒ์ง€ ๋„๋Š” ๋ฃจํ”„ ์•ˆ์—์„œ ๋งค๋ฒˆ RCON[n] ์„ ์„ž๋Š”๋‹ค. 0x1333~0x1362 ๊ตฌ๊ฐ„์— k ๋กœ ๊ฐˆ๋ผ์ง€๋Š” ๋ถ„๊ธฐ๊ฐ€ ์—†๋‹ค.

โ–ถ๐Ÿ› ์‚ฝ์งˆ 3 โ€” ์—ด ํšŒ์ „ ๋ฐฉํ–ฅ์„ ๋ฐ˜๋Œ€๋กœ ์žก์•˜๋‹ค

"์–ด์ฐจํ”ผ 10๋ผ์šด๋“œ๋ฉด ์ƒ์‡„๋˜๋‹ˆ ๋ฐฉํ–ฅ์€ ์ƒ๊ด€์—†์ง€ ์•Š๋‚˜" ๋ผ๊ณ  ์ž ๊น ์ƒ๊ฐํ–ˆ๋‹ค. ํ‹€๋ ธ๋‹ค.

์ž๋ฆฌ ์ˆœ์—ด์˜ ์ตœ์ข… ๊ฒฐ๊ณผ๋Š” ํ•ญ๋“ฑ์ด ๋งž์ง€๋งŒ, ๋ผ์šด๋“œ ์‚ฌ์ด์‚ฌ์ด์— AddRoundKey ๊ฐ€ ๋ผ์–ด๋“ ๋‹ค. ๋ผ์šด๋“œํ‚ค ๋ฐ”์ดํŠธ๊ฐ€ ์–ด๋А ์ž๋ฆฌ์— ์–นํžˆ๋Š”์ง€๋Š” ๊ทธ ์‹œ์ ์˜ ๋ฐฐ์—ด์— ๋‹ฌ๋ ค ์žˆ์œผ๋ฏ€๋กœ, ๋ฐฉํ–ฅ์„ ๋’ค์ง‘์œผ๋ฉด ์ค‘๊ฐ„ ๋Œ€์‘์ด ์ „๋ถ€ ๋‹ฌ๋ผ์ง„๋‹ค.

๊ฒฐ๊ณผ๋Š” ์—ญ์‹œ ์˜ˆ์™ธ ์—†๋Š” 25๋ฐ”์ดํŠธ ์“ฐ๋ ˆ๊ธฐ๋‹ค.

โ–ถ๐Ÿ› ์‚ฝ์งˆ 4 โ€” ์—ด์ด ์•„๋‹ˆ๋ผ ํ–‰์„ ๋Œ๋ฆฐ๋‹ค๊ณ  ์ฝ์—ˆ๋‹ค

๊ฐ€์žฅ ๊ทธ๋Ÿด๋“ฏํ•œ ์˜ค๋…์ด๋‹ค. AES ๋ฅผ ์•„๋Š” ์‚ฌ๋žŒ์ผ์ˆ˜๋ก 0x15fb ์„ ๋ณด๊ณ  "์•„ ShiftRows ๊ตฌ๋‚˜" ํ•˜๊ณ  ๋„˜์–ด๊ฐ€๊ธฐ ์‰ฝ๋‹ค.

๊ตฌ๋ถ„์ ์€ ์˜คํ”„์…‹ ๊ฐ„๊ฒฉ ํ•˜๋‚˜๋‹ค. ํ–‰์„ ๋Œ๋ฆฐ๋‹ค๋ฉด ์ธ์ ‘ํ•œ i, i+1, i+2 โ€ฆ ๋ฅผ ๊ฑด๋“œ๋ ค์•ผ ํ•˜๋Š”๋ฐ, ์‹ค์ œ๋กœ๋Š” i, i+5, i+10 โ€ฆ ์ด๋‹ค. 5์นธ์”ฉ ๊ฑด๋„ˆ๋›ฐ๋‹ˆ ์—ด์ด๋‹ค.

ํ•œ ๊ฐ€์ง€ ๋”. 25๋ฐ”์ดํŠธ ๋ธ”๋ก์ด๋ผ ์ง„์งœ AES ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋Š” ์• ์ดˆ์— ๋ชป ์“ด๋‹ค. Crypto.Cipher.AES.new ์— 25๋ฐ”์ดํŠธ ํ‚ค๋ฅผ ์ฃผ๋ฉด Incorrect AES key length (25 bytes) ๋กœ ๊ฑฐ๋ถ€๋‹นํ•œ๋‹ค. "AES ๋‹ˆ๊นŒ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋กœ ํ’€๋ฉด ๋˜๊ฒ ์ง€" ๋ผ๋Š” ๊ธธ์€ ์ฒ˜์Œ๋ถ€ํ„ฐ ๋ง‰ํ˜€ ์žˆ๋Š” ์…ˆ์ด๋‹ค.



โœ… ๊ฒ€์ฆ โ€” ๋ˆˆ์ด ์•„๋‹ˆ๋ผ ๋ฐ”์ด๋„ˆ๋ฆฌ๊ฐ€ ํŒ์ •ํ•˜๊ฒŒ

์‚ฝ์งˆ ๋„ท์ด ์ „๋ถ€ "๊ทธ๋Ÿด๋“ฏํ•œ 25๋ฐ”์ดํŠธ"์˜€๋‹ค๋Š” ๊ฒŒ ์š”์ ์ด๋‹ค. ๋ˆˆ์œผ๋กœ ๋ณด๊ณ  ๋งž๋‹ค๊ณ  ํ•˜๋ฉด ์•ˆ ๋œ๋‹ค. ํŒ์ •์€ ๋„๊ตฌ์— ๋„˜๊ธฐ๊ณ  ์„ธ ๊ฐ€์ง€ ๊ฒฝ๋กœ๋กœ ๋”ฐ๋กœ ํ™•์ธํ–ˆ๋‹ค.

1) ์žฌ๊ตฌ์„ฑํ•œ C ์†Œ์Šค๊ฐ€ ๊ฐ™์€ ์•”ํ˜ธ๋ฌธ์„ ๋‚ธ๋‹ค

๋””์ปดํŒŒ์ผ ๊ฒฐ๊ณผ๋ฅผ C ๋กœ ๋‹ค์‹œ ์จ์„œ, ๊ฐ™์€ ํ‘œ๋ฅผ ์ฝ๊ณ  ๊ฐ™์€ ์•”ํ˜ธ๋ฌธ์ด ๋‚˜์˜ค๋Š”์ง€ ๋ณธ๋‹ค. ํ•จ์ˆ˜ ์ด๋ฆ„์€ ํ•˜๋Š” ์ผ์„ ๋ณด๊ณ  ๋ถ™์˜€๊ณ , ์ธ๋ฑ์Šค ๊ณ„์‚ฐ์€ objdump ๊ทธ๋Œ€๋กœ๋‹ค.

/* locked present โ€” ๋””์ปดํŒŒ์ผ ๊ฒฐ๊ณผ๋ฅผ ๊ทธ๋Œ€๋กœ ์˜ฎ๊ธด ์žฌ๊ตฌ์„ฑ ์†Œ์Šค.
 *
 * ์›๋ณธ prob ์€ stripped ๋ผ ์ด๋ฆ„์ด ์—†๋‹ค. ์•„๋ž˜ ์ด๋ฆ„์€ ํ•˜๋Š” ์ผ์„ ๋ณด๊ณ  ๋ถ™์ธ ๊ฒƒ์ด๊ณ ,
 * ์—ฐ์‚ฐ ์ˆœ์„œยท์ธ๋ฑ์Šค ๊ณ„์‚ฐ์€ objdump ์ถœ๋ ฅ ๊ทธ๋Œ€๋กœ๋‹ค.
 *
 *   gcc -O0 -no-pie -o recon recon.c
 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
 
#define NR 10                 /* encrypt 0x174d: ๋ผ์šด๋“œ 1..10 */
#define BS 25                 /* 5 x 5 ์ƒํƒœ */
 
/* .rodata 0x2040 โ€” ํ‘œ์ค€ AES S-box */
static unsigned char SBOX[256];
/* .rodata 0x2020 โ€” ํ‘œ์ค€ AES Rcon (8d 01 02 04 08 10 20 40 80 1b 36) */
static unsigned char RCON[16];
/* .data 0x4030 */
static unsigned char KEY[BS];
/* .data 0x4010 โ€” ์ •๋‹ต ์•”ํ˜ธ๋ฌธ */
static unsigned char CIPHER[BS];
 
/* 0x11e9 โ€” 5๋ฐ”์ดํŠธ๋ฅผ ์™ผ์ชฝ์œผ๋กœ 1์นธ ํšŒ์ „ */
static void rot5(unsigned char *p)
{
    unsigned char t = p[0];
    p[0] = p[1]; p[1] = p[2]; p[2] = p[3]; p[3] = p[4]; p[4] = t;
}
 
/* 0x1254 โ€” ๋ผ์šด๋“œํ‚ค 11๊ฐœ(275๋ฐ”์ดํŠธ, main ์˜ malloc(0x113)) */
static void key_expand(unsigned char *rk, const unsigned char *key)
{
    unsigned char temp[5];
    int n, i, j, k;
 
    for (i = 0; i <= 24; i++)
        rk[i] = key[i];
 
    /* ์—ฌ๊ธฐ๊ฐ€ ์ง„์งœ AES ์™€ ๋‹ค๋ฅด๋‹ค: ๋งˆ์ง€๋ง‰ ํ–‰(20..24)์ด ์•„๋‹ˆ๋ผ ํ–‰ 3(15..19)์„ ์ง‘๋Š”๋‹ค */
    for (i = 0; i <= 4; i++)
        temp[i] = rk[i + 15];
 
    for (n = 1; n <= NR; n++) {
        rot5(temp);
        for (k = 0; k <= 4; k++)
            /* Rcon ์ด ์ฒซ ๋ฐ”์ดํŠธ๊ฐ€ ์•„๋‹ˆ๋ผ 5๋ฐ”์ดํŠธ ์ „๋ถ€์— XOR ๋œ๋‹ค */
            rk[25 * n + k] = rk[25 * (n - 1) + k] ^ SBOX[temp[k]] ^ RCON[n];
        for (i = 1; i <= 4; i++) {
            for (j = 0; j <= 4; j++) {
                rk[25 * n + 5 * i + j] =
                    rk[25 * n + 5 * (i - 1) + j] ^ rk[25 * (n - 1) + 5 * i + j];
                temp[j] = rk[25 * n + 5 * i + j];
            }
        }
    }
}
 
/* 0x14a7 */
static void add_round_key(unsigned char r, unsigned char *st, const unsigned char *rk)
{
    unsigned char i, j;
    for (i = 0; i <= 4; i++)
        for (j = 0; j <= 4; j++)
            st[5 * i + j] ^= rk[25 * r + 5 * i + j];
}
 
/* 0x1572 */
static void sub_bytes(unsigned char *st)
{
    unsigned char i, j;
    for (i = 0; i <= 4; i++)
        for (j = 0; j <= 4; j++)
            st[5 * j + i] = SBOX[st[5 * j + i]];
}
 
/* 0x15fb โ€” ์—ด i ๋ฅผ i ๋ฒˆ ์œ„๋กœ ํšŒ์ „. AES ์˜ ShiftRows ๋ฅผ ์ „์น˜ํ•œ ๋ชจ์–‘์ด๋‹ค */
static void shift_cols(unsigned char *st)
{
    unsigned char i, c, t;
    for (i = 0; i <= 4; i++) {
        for (c = 0; c < i; c++) {
            t = st[i];
            st[i]      = st[i + 5];
            st[i + 5]  = st[i + 10];
            st[i + 10] = st[i + 15];
            st[i + 15] = st[i + 20];
            st[i + 20] = t;
        }
    }
}
 
/* 0x16e2 โ€” MixColumns ๊ฐ€ ์—†๋‹ค */
static void encrypt(unsigned char *st, const unsigned char *rk)
{
    unsigned char r;
    add_round_key(0, st, rk);
    for (r = 1; r <= NR; r++) {
        sub_bytes(st);
        shift_cols(st);
        add_round_key(r, st, rk);
    }
}
 
/* ์›๋ณธ ๋ฐ”์ด๋„ˆ๋ฆฌ์—์„œ ํ‘œ๋ฅผ ๊ทธ๋Œ€๋กœ ๋–  ์˜จ๋‹ค (ํ•˜๋“œ์ฝ”๋”ฉ ๋Œ€์‹ ) */
static void load_tables(const char *path)
{
    FILE *f = fopen(path, "rb");
    if (!f) { perror("fopen"); exit(2); }
    fseek(f, 0x2040, SEEK_SET); fread(SBOX,   1, 256, f);
    fseek(f, 0x2020, SEEK_SET); fread(RCON,   1, 16,  f);
    fseek(f, 0x3010, SEEK_SET); fread(CIPHER, 1, BS,  f);  /* .data vaddr 0x4010 -> off 0x3010 */
    fseek(f, 0x3030, SEEK_SET); fread(KEY,    1, BS,  f);
    fclose(f);
}
 
int main(int argc, char **argv)
{
    unsigned char rk[25 * (NR + 1)];
    unsigned char st[BS];
    int i;
 
    load_tables(argc > 1 ? argv[1] : "extracted/prob");
    key_expand(rk, KEY);
 
    if (argc > 2) {                    /* ์ž„์˜ ํ‰๋ฌธ์„ ์•”ํ˜ธํ™”ํ•ด ๋ณธ๋‹ค */
        memcpy(st, argv[2], BS);
    } else {                           /* ๊ธฐ๋ณธ: ์šฐ๋ฆฌ๊ฐ€ ์ฐพ์€ ๋น„๋ฐ€๋ฒˆํ˜ธ */
        memcpy(st, "DH{W0w_U_kn0w_4b0ut_AES?}", BS);
    }
    printf("plain  : %.25s\n", st);
    encrypt(st, rk);
    printf("cipher : ");
    for (i = 0; i < BS; i++) printf("%02x", st[i]);
    printf("\n.data  : ");
    for (i = 0; i < BS; i++) printf("%02x", CIPHER[i]);
    printf("\nmatch  : %s\n", memcmp(st, CIPHER, BS) == 0 ? "YES" : "no");
    return memcmp(st, CIPHER, BS) != 0;
}
gcc -O0 -no-pie -o recon recon.c && ./recon extracted/prob

recon.c ๋ฅผ gcc -O0 ๋กœ ๋นŒ๋“œํ•ด ์‹คํ–‰ํ•œ ๊ฒฐ๊ณผ โ€” ๋ณต๊ตฌํ•œ ๋น„๋ฐ€๋ฒˆํ˜ธ๋ฅผ ๋„ฃ์œผ๋ฉด data 0x4010 ์— ๋ฐ•ํ˜€ ์žˆ๋Š” ์ •๋‹ต ์•”ํ˜ธ๋ฌธ๊ณผ 25๋ฐ”์ดํŠธ๊ฐ€ ์ „๋ถ€ ์ผ์น˜ํ•ด match YES ๊ฐ€ ๋œฌ๋‹ค
recon.c ๋ฅผ gcc -O0 ๋กœ ๋นŒ๋“œํ•ด ์‹คํ–‰ํ•œ ๊ฒฐ๊ณผ โ€” ๋ณต๊ตฌํ•œ ๋น„๋ฐ€๋ฒˆํ˜ธ๋ฅผ ๋„ฃ์œผ๋ฉด data 0x4010 ์— ๋ฐ•ํ˜€ ์žˆ๋Š” ์ •๋‹ต ์•”ํ˜ธ๋ฌธ๊ณผ 25๋ฐ”์ดํŠธ๊ฐ€ ์ „๋ถ€ ์ผ์น˜ํ•ด match YES ๊ฐ€ ๋œฌ๋‹ค

2) ์‹ค์ œ ํ”„๋กœ์„ธ์Šค์˜ ๋ผ์šด๋“œ๋ณ„ ์ƒํƒœ๋ฅผ ๋œฌ๋‹ค

์žฌ๊ตฌํ˜„์ด ๋งž๋Š”์ง€๋Š” ๊ฒฐ๊ตญ ์ง„์งœ ์‹คํ–‰๊ณผ ๋Œ€์กฐํ•ด์•ผ ํ•œ๋‹ค. gdb ๋กœ encrypt ์•ˆ์— ๋ธŒ๋ ˆ์ดํฌ๋ฅผ ๊ฑธ๊ณ  ๋ผ์šด๋“œ๋งˆ๋‹ค ์ƒํƒœ 25๋ฐ”์ดํŠธ๋ฅผ ํ†ต์งธ๋กœ ์ฝ๋Š”๋‹ค. PIE ๋ผ ๋กœ๋“œ ๋ฒ ์ด์Šค๋Š” ๊ด€๋ก€๋กœ ๊ฐ€์ •ํ•˜์ง€ ์•Š๊ณ  info proc mappings ์—์„œ ์ง์ ‘ ์ฝ์—ˆ๋‹ค.

# ์‹ค์ œ prob ํ”„๋กœ์„ธ์Šค์˜ ๋ผ์šด๋“œ๋ณ„ ์ƒํƒœ๋ฅผ ๊ทธ๋Œ€๋กœ ๋– ์„œ ํŒŒ์ด์ฌ ์žฌ๊ตฌํ˜„๊ณผ ๋Œ€์กฐํ•œ๋‹ค.
#   gdb -batch -x trace_rounds.gdb
set confirm off
set pagination off
file ./extracted/prob
starti
python
# PIE ๋ฒ ์ด์Šค๋ฅผ ๊ด€๋ก€๋กœ ๊ฐ€์ •ํ•˜์ง€ ์•Š๋Š”๋‹ค โ€” ๋งคํ•‘์—์„œ ์ง์ ‘ ์ฝ๋Š”๋‹ค
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("/prob"))
print("PIE base = %s" % hex(base))
gdb.execute("break *%s" % hex(base + 0x170F))   # encrypt: AddRoundKey(0) ์งํ›„
gdb.execute("break *%s" % hex(base + 0x1743))   # encrypt: ๊ฐ ๋ผ์šด๋“œ AddRoundKey(r) ์งํ›„
gdb.execute("run < ./pw.txt", to_string=True)
 
inf = gdb.selected_inferior()
print("master key .data@0x4030 : %r" % bytes(inf.read_memory(base + 0x4030, 25)))
print("cipher   .data@0x4010 : %s" % bytes(inf.read_memory(base + 0x4010, 25)).hex())
print("round key[0..24]      : %s" %
      bytes(inf.read_memory(int(gdb.parse_and_eval("*(unsigned long*)($rbp-0x20)")), 25)).hex())
 
for r in range(11):
    ptr = int(gdb.parse_and_eval("*(unsigned long*)($rbp-0x18)"))
    print("round %2d state : %s" % (r, bytes(inf.read_memory(ptr, 25)).hex()))
    if r < 10:
        gdb.execute("continue", to_string=True)
end
quit
gdb -batch -x trace_rounds.gdb

gdb -batch ๋กœ ๋œฌ ์‹ค์ œ prob ํ”„๋กœ์„ธ์Šค์˜ ๋ผ์šด๋“œ๋ณ„ ์ƒํƒœ โ€” PIE ๋ฒ ์ด์Šค๋ฅผ ๋งคํ•‘์—์„œ ์ฝ์–ด ๋ธŒ๋ ˆ์ดํฌํฌ์ธํŠธ๋ฅผ ๊ฑธ๊ณ  ๋ผ์šด๋“œ 0๋ถ€ํ„ฐ 10๊นŒ์ง€ 25๋ฐ”์ดํŠธ์”ฉ ๋คํ”„ํ–ˆ๋‹ค. ๋ผ์šด๋“œ 10 ์˜ ์ƒํƒœ๊ฐ€ ๊ณง data ์˜ ์ •๋‹ต ์•”ํ˜ธ๋ฌธ์ด๋‹ค
gdb -batch ๋กœ ๋œฌ ์‹ค์ œ prob ํ”„๋กœ์„ธ์Šค์˜ ๋ผ์šด๋“œ๋ณ„ ์ƒํƒœ โ€” PIE ๋ฒ ์ด์Šค๋ฅผ ๋งคํ•‘์—์„œ ์ฝ์–ด ๋ธŒ๋ ˆ์ดํฌํฌ์ธํŠธ๋ฅผ ๊ฑธ๊ณ  ๋ผ์šด๋“œ 0๋ถ€ํ„ฐ 10๊นŒ์ง€ 25๋ฐ”์ดํŠธ์”ฉ ๋คํ”„ํ–ˆ๋‹ค. ๋ผ์šด๋“œ 10 ์˜ ์ƒํƒœ๊ฐ€ ๊ณง data ์˜ ์ •๋‹ต ์•”ํ˜ธ๋ฌธ์ด๋‹ค

๋ผ์šด๋“œ 10 ์˜ ์ƒํƒœ๊ฐ€ .data 0x4010 ์˜ ์•”ํ˜ธ๋ฌธ๊ณผ ๊ฐ™๋‹ค. ๋‹น์—ฐํ•˜์ง€๋งŒ ์ค‘๊ฐ„ ์•„ํ™‰ ๊ฐœ๊ฐ€ ๋” ์ค‘์š”ํ•˜๋‹ค. ๊ทธ๊ฑธ ํŒŒ์ด์ฌ ์žฌ๊ตฌํ˜„๊ณผ ํ•œ ์ค„์”ฉ ๋Œ€์กฐํ•œ๋‹ค.

#!/usr/bin/env python3
"""gdb ๋กœ ๋œฌ ์‹ค์ œ ํ”„๋กœ์„ธ์Šค์˜ ๋ผ์šด๋“œ๋ณ„ ์ƒํƒœ์™€ ํŒŒ์ด์ฌ ์žฌ๊ตฌํ˜„์„ ํ•œ ๋ผ์šด๋“œ์”ฉ ๋Œ€์กฐํ•œ๋‹ค.
 
gdb_rounds.txt ๋Š” trace_rounds.gdb ๊ฐ€ ๋งŒ๋“ ๋‹ค:
    gdb -batch -x trace_rounds.gdb | grep -E '^round +[0-9]+ state' > gdb_rounds.txt
"""
import re
from pathlib import Path
import cipher
 
live = {}
for line in Path("gdb_rounds.txt").read_text().splitlines():
    m = re.match(r"round\s+(\d+) state : ([0-9a-f]{50})", line)
    if m:
        live[int(m.group(1))] = bytes.fromhex(m.group(2))
 
rk = cipher.key_expand()
st = bytearray(b"DH{W0w_U_kn0w_4b0ut_AES?}")
cipher.add_round_key(st, rk, 0)
 
ok = True
for r in range(11):
    if r:
        cipher.sub_bytes(st)
        cipher.shift_cols(st)
        cipher.add_round_key(st, rk, r)
    same = bytes(st) == live[r]
    ok &= same
    print(f"round {r:2d}  py={bytes(st).hex()}  gdb={'์ผ์น˜' if same else '๋ถˆ์ผ์น˜'}")
 
print()
print("11๊ฐœ ๋ผ์šด๋“œ ์ƒํƒœ ์ „๋ถ€ ์ผ์น˜" if ok else "๋ถˆ์ผ์น˜ ๋ฐœ์ƒ โ€” ์žฌ๊ตฌํ˜„์ด ํ‹€๋ ธ๋‹ค")
assert ok
gdb -batch -x trace_rounds.gdb | grep -E "^round +[0-9]+ state" > gdb_rounds.txt && python3 verify_rounds.py

verify_rounds.py ์‹คํ–‰ ๊ฒฐ๊ณผ โ€” gdb ๋กœ ๋œฌ ์‹ค์ œ ํ”„๋กœ์„ธ์Šค์˜ ๋ผ์šด๋“œ ์ƒํƒœ์™€ ํŒŒ์ด์ฌ ์žฌ๊ตฌํ˜„์˜ ์ƒํƒœ๋ฅผ ๋ผ์šด๋“œ 0๋ถ€ํ„ฐ 10๊นŒ์ง€ ํ•˜๋‚˜์”ฉ ๋Œ€์กฐํ•ด 11๊ฐœ๊ฐ€ ์ „๋ถ€ ์ผ์น˜ํ•œ๋‹ค
verify_rounds.py ์‹คํ–‰ ๊ฒฐ๊ณผ โ€” gdb ๋กœ ๋œฌ ์‹ค์ œ ํ”„๋กœ์„ธ์Šค์˜ ๋ผ์šด๋“œ ์ƒํƒœ์™€ ํŒŒ์ด์ฌ ์žฌ๊ตฌํ˜„์˜ ์ƒํƒœ๋ฅผ ๋ผ์šด๋“œ 0๋ถ€ํ„ฐ 10๊นŒ์ง€ ํ•˜๋‚˜์”ฉ ๋Œ€์กฐํ•ด 11๊ฐœ๊ฐ€ ์ „๋ถ€ ์ผ์น˜ํ•œ๋‹ค

11๊ฐœ ๋ผ์šด๋“œ๊ฐ€ ์ „๋ถ€ ์ผ์น˜ํ•œ๋‹ค. ์ค‘๊ฐ„ ์ƒํƒœ๊นŒ์ง€ ๋งž์•˜์œผ๋‹ˆ ํ‚ค ํ™•์žฅยทS-boxยท์—ด ํšŒ์ „ ์…‹ ๋‹ค ์ œ๋Œ€๋กœ ์˜ฎ๊ธด ๊ฒƒ์ด๋‹ค.

3) ๋ฌธ์ œ ๋ฐ”์ด๋„ˆ๋ฆฌ์— ์ง์ ‘ ๋„ฃ๋Š”๋‹ค

๋งˆ์ง€๋ง‰์€ ๋ฌธ์ œ๊ฐ€ ์Šค์Šค๋กœ ๋‹ตํ•˜๊ฒŒ ํ•œ๋‹ค. ๋Œ€์กฐ๊ตฐ์œผ๋กœ ํ•œ ๊ธ€์ž ๋ฐ”๊พผ ๊ฒƒ๊ณผ ํ•œ ๊ธ€์ž ๋บ€ ๊ฒƒ๋„ ๊ฐ™์ด ๋„ฃ์—ˆ๋‹ค.

#!/usr/bin/env python3
"""์ฐพ์•„๋‚ธ ๋น„๋ฐ€๋ฒˆํ˜ธ๋ฅผ ๋ฌธ์ œ ๋ฐ”์ด๋„ˆ๋ฆฌ์— ์‹ค์ œ๋กœ ๋„ฃ์–ด ํŒ์ •์„ ๋ฐ›๋Š”๋‹ค.
 
ํ•œ ๊ธ€์ž๋งŒ ๋ฐ”๊พผ ๋Œ€์กฐ๊ตฐ์„ ๊ฐ™์ด ๋Œ๋ ค 'correct' ๊ฐ€ ์šฐ์—ฐ์ด ์•„๋‹˜์„ ๋ณด์ธ๋‹ค.
"""
import subprocess
 
PW = "DH{W0w_U_kn0w_4b0ut_AES?}"
CASES = [
    ("์ •๋‹ต", PW),
    ("๋งˆ์ง€๋ง‰ S ๋ฅผ s ๋กœ", PW.replace("AES", "AEs")),
    ("๊ธธ์ด 24 (๋งˆ์ง€๋ง‰ } ์ œ๊ฑฐ)", PW[:-1]),
]
 
for label, pw in CASES:
    r = subprocess.run(["./extracted/prob"], input=pw + "\n",
                       capture_output=True, text=True)
    print(f"[{label}]")
    print(f"  ์ž…๋ ฅ   : {pw}")
    print(f"  ์ถœ๋ ฅ   : {r.stdout.strip()}")
    print(f"  ์ข…๋ฃŒ์ฝ”๋“œ: {r.returncode}")
python3 verify.py

verify.py ์‹คํ–‰ ๊ฒฐ๊ณผ โ€” ๋ณต๊ตฌํ•œ ๋น„๋ฐ€๋ฒˆํ˜ธ๋ฅผ ๋„ฃ์œผ๋ฉด correct ์™€ ์ข…๋ฃŒ์ฝ”๋“œ 0 ์ด๊ณ  ๋งˆ์ง€๋ง‰ S ๋ฅผ ์†Œ๋ฌธ์ž๋กœ ๋ฐ”๊พธ๊ฑฐ๋‚˜ ๋‹ซ๋Š” ๊ด„ํ˜ธ๋ฅผ ๋นผ๋ฉด wrong ๊ณผ ์ข…๋ฃŒ์ฝ”๋“œ 1 ์ด ๋‚˜์˜จ๋‹ค
verify.py ์‹คํ–‰ ๊ฒฐ๊ณผ โ€” ๋ณต๊ตฌํ•œ ๋น„๋ฐ€๋ฒˆํ˜ธ๋ฅผ ๋„ฃ์œผ๋ฉด correct ์™€ ์ข…๋ฃŒ์ฝ”๋“œ 0 ์ด๊ณ  ๋งˆ์ง€๋ง‰ S ๋ฅผ ์†Œ๋ฌธ์ž๋กœ ๋ฐ”๊พธ๊ฑฐ๋‚˜ ๋‹ซ๋Š” ๊ด„ํ˜ธ๋ฅผ ๋นผ๋ฉด wrong ๊ณผ ์ข…๋ฃŒ์ฝ”๋“œ 1 ์ด ๋‚˜์˜จ๋‹ค



๐Ÿ”“ ํ‚ค๋ฅผ ๋ชฐ๋ผ๋„ ์—ด๋ฆฐ๋‹ค โ€” ์กฐ๊ธฐ์ข…๋ฃŒ ์˜ค๋ผํด

์—ฌ๊ธฐ๊นŒ์ง€๋Š” .data ์˜ ๋งˆ์Šคํ„ฐํ‚ค๋ฅผ ์ฝ์–ด์„œ ํ‘ผ ๊ฒƒ์ด๋‹ค. ๊ทธ๋Ÿฐ๋ฐ ์ด ๋ฌธ์ œ๋Š” ์•”ํ˜ธ๋ฅผ ํ•œ ์ค„๋„ ์—ญ์‚ฐํ•˜์ง€ ์•Š๊ณ ๋„ ๋šซ๋ฆฐ๋‹ค. main ์˜ ๋งˆ์ง€๋ง‰ ๋น„๊ต ๋ฃจํ”„๊ฐ€ ์ƒˆ๋Š” ๊ณณ์ด๋‹ค.

objdump -d -M intel extracted/prob --start-address=0x1868 --stop-address=0x1910 | sed -E -f annot_main.sed

objdump ๋กœ ๋ณธ main ์˜ ๋น„๊ต ๋ฃจํ”„ โ€” ์•”ํ˜ธํ™”ํ•œ ์ƒํƒœ์™€ data 0x4010 ์˜ ์ •๋‹ต์„ ํ•œ ๋ฐ”์ดํŠธ์”ฉ cmp ํ•˜๋‹ค๊ฐ€ ๋‹ค๋ฅด๋ฉด ๊ทธ ์ž๋ฆฌ์—์„œ puts wrong ๊ณผ exit 1 ๋กœ ๋น ์ ธ๋‚˜๊ฐ„๋‹ค. ๋‚จ์€ ๋ฐ”์ดํŠธ๋Š” ์•„์˜ˆ ๋น„๊ตํ•˜์ง€ ์•Š๋Š”๋‹ค
objdump ๋กœ ๋ณธ main ์˜ ๋น„๊ต ๋ฃจํ”„ โ€” ์•”ํ˜ธํ™”ํ•œ ์ƒํƒœ์™€ data 0x4010 ์˜ ์ •๋‹ต์„ ํ•œ ๋ฐ”์ดํŠธ์”ฉ cmp ํ•˜๋‹ค๊ฐ€ ๋‹ค๋ฅด๋ฉด ๊ทธ ์ž๋ฆฌ์—์„œ puts wrong ๊ณผ exit 1 ๋กœ ๋น ์ ธ๋‚˜๊ฐ„๋‹ค. ๋‚จ์€ ๋ฐ”์ดํŠธ๋Š” ์•„์˜ˆ ๋น„๊ตํ•˜์ง€ ์•Š๋Š”๋‹ค

cmp cl,al ์ด ์–ด๊ธ‹๋‚˜๋ฉด ๊ณง๋ฐ”๋กœ puts("wrong") + exit(1) ์ด๋‹ค. ๋‚จ์€ ๋ฐ”์ดํŠธ๋Š” ๋น„๊ต์กฐ์ฐจ ํ•˜์ง€ ์•Š๋Š”๋‹ค. ์ฆ‰ ๋ช‡ ๋ฒˆ์งธ์—์„œ ํ‹€๋ ธ๋Š”์ง€๊ฐ€ ํ”„๋กœ๊ทธ๋žจ ์ƒํƒœ์— ๋‚จ๋Š”๋‹ค. ํ™”๋ฉด์—๋Š” ์–ด๋А ์ชฝ์ด๋“  wrong ๋งŒ ์ฐํžˆ์ง€๋งŒ, ๋ฃจํ”„ ๋ณ€์ˆ˜ i(rbp-0xa0)์™€ j(rbp-0x9c)๋ฅผ ์ฝ์œผ๋ฉด ์ฒซ ๋ถˆ์ผ์น˜ ์œ„์น˜๊ฐ€ ๊ทธ๋Œ€๋กœ ๋‚˜์˜จ๋‹ค.

์—ฌ๊ธฐ์— ์•ž์—์„œ ํ™•์ธํ•œ ์„ฑ์งˆ์ด ๋ถ™๋Š”๋‹ค. ํ™•์‚ฐ์ด 0 ์ด๊ณ  ์ž๋ฆฌ ์ˆœ์—ด์ด ํ•ญ๋“ฑ์ด๋‹ˆ, ์ž๋ฆฌ p ์˜ ๋น„๊ต ๊ฒฐ๊ณผ๋Š” ์ž…๋ ฅ ๋ฐ”์ดํŠธ p ํ•˜๋‚˜์—๋งŒ ๋‹ฌ๋ ค ์žˆ๋‹ค. ๊ทธ๋Ÿฌ๋ฉด ์•ž์—์„œ๋ถ€ํ„ฐ ํ•œ ๊ธ€์ž์”ฉ ํ™•์ •ํ•ด ๋‚˜๊ฐˆ ์ˆ˜ ์žˆ๋‹ค.

gdb ๋ฅผ ๋ถ™์—ฌ ์ž๋™ํ™”ํ–ˆ๋‹ค. run ์„ ์„ธ์…˜ ์•ˆ์—์„œ ๋ฐ˜๋ณตํ•˜๋Š” ๋ฐฉ์‹์ด๋ผ gdb ๊ธฐ๋™ ๋น„์šฉ์ด ํ•œ ๋ฒˆ๋งŒ ๋“ ๋‹ค.

# gdb -batch -x oracle_attack.py ๋กœ ๋Œ๋ฆฐ๋‹ค.
#
# main ์˜ ๋งˆ์ง€๋ง‰ ๋น„๊ต ๋ฃจํ”„(0x1874~0x18d5)๋Š” ์ฒซ ๋ถˆ์ผ์น˜์—์„œ ๊ณง๋ฐ”๋กœ puts("wrong") + exit(1) ํ•œ๋‹ค.
# ์ฆ‰ "๋ช‡ ๋ฒˆ์งธ ๋ฐ”์ดํŠธ๊นŒ์ง€ ๋งž์•˜๋Š”๊ฐ€"๊ฐ€ ํ”„๋กœ๊ทธ๋žจ ๋‚ด๋ถ€ ์ƒํƒœ์— ๋‚จ๋Š”๋‹ค.
# ์•”ํ˜ธ๋ฅผ ํ•œ ์ค„๋„ ์—ญ์‚ฐํ•˜์ง€ ์•Š๊ณ  ์ด ์กฐ๊ธฐ์ข…๋ฃŒ๋งŒ ์ด์šฉํ•ด ๋น„๋ฐ€๋ฒˆํ˜ธ๋ฅผ ์ž๋ฆฌ๋ณ„๋กœ ๋ณต๊ตฌํ•œ๋‹ค.
import string, time
 
WRONG = 0x18C4      # lea rdi,"wrong"   โ€” ์ฒซ ๋ถˆ์ผ์น˜ ์ง€์ 
DONE  = 0x18FE      # lea rdi,"correct" โ€” 25๋ฐ”์ดํŠธ ์ „๋ถ€ ์ผ์น˜
IDX_I = 0xA0        # main ๋ฐ”๊นฅ ๋ฃจํ”„ ๋ณ€์ˆ˜ i ๋Š” rbp-0xa0
IDX_J = 0x9C        # ์•ˆ์ชฝ ๋ฃจํ”„ ๋ณ€์ˆ˜ j ๋Š” rbp-0x9c
INFILE = "/tmp/lp_oracle_in"
 
gdb.execute("set confirm off")
gdb.execute("set pagination off")
gdb.execute("file ./extracted/prob")
gdb.execute("starti", to_string=True)
 
# PIE ๋ผ ๋กœ๋“œ ๋ฒ ์ด์Šค๋ฅผ ๊ด€๋ก€๋กœ ๊ฐ€์ •ํ•˜์ง€ ์•Š๊ณ  ์‹ค์ œ ๋งคํ•‘์—์„œ ์ฝ๋Š”๋‹ค.
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("/prob"))
print(f"[*] PIE base = {hex(base)}")
 
gdb.execute(f"break *{hex(base + WRONG)}", to_string=True)
gdb.execute(f"break *{hex(base + DONE)}", to_string=True)
gdb.execute("kill", to_string=True)
 
 
def probe(guess: bytes) -> int:
    """guess ๋ฅผ ๋„ฃ๊ณ  '๋ช‡ ๋ฒˆ์งธ ๋ฐ”์ดํŠธ์—์„œ ์ฒ˜์Œ ํ‹€๋ ธ๋Š”์ง€'๋ฅผ ๋Œ๋ ค์ค€๋‹ค. 25 ๋ฉด ์ „๋ถ€ ์ •๋‹ต."""
    with open(INFILE, "wb") as f:
        f.write(guess + b"\n")
    gdb.execute(f"run < {INFILE}", to_string=True)
    stopped_at = int(gdb.parse_and_eval("$pc"))
    if stopped_at == base + DONE:
        gdb.execute("kill", to_string=True)
        return 25
    i = int(gdb.parse_and_eval(f"*(int*)($rbp-{hex(IDX_I)})"))
    j = int(gdb.parse_and_eval(f"*(int*)($rbp-{hex(IDX_J)})"))
    gdb.execute("kill", to_string=True)
    return 5 * i + j
 
 
# scanf("%s") ๋ผ ๊ณต๋ฐฑ/NUL ์€ ์• ์ดˆ์— ๋ชป ๋„ฃ๋Š”๋‹ค. ํƒ์ƒ‰์€ ์ถœ๋ ฅ ๊ฐ€๋Šฅ ๋ฌธ์ž๋กœ ์ถฉ๋ถ„ํ•˜๋‹ค.
ALPHABET = (string.ascii_letters + string.digits + "{}_?!@#$%^&*()-+=[]<>.,:;/\\|~`'\"").encode()
FILLER = b"A"
 
t0 = time.time()
known = b""
runs = 0
for pos in range(25):
    for c in ALPHABET:
        cand = known + bytes([c]) + FILLER * (24 - pos)
        runs += 1
        if probe(cand) > pos:
            known += bytes([c])
            print(f"[{pos:2d}] {chr(c)!r} ํ™•์ • -> {known.decode()}")
            break
    else:
        print(f"[!] ์ž๋ฆฌ {pos} ์—์„œ ํ›„๋ณด ์†Œ์ง„")
        break
 
print()
print(f"password = {known.decode()}")
print(f"[*] ๋ฐ”์ด๋„ˆ๋ฆฌ ์‹คํ–‰ {runs}ํšŒ / {time.time() - t0:.1f}์ดˆ โ€” ๋ณตํ˜ธ ๋ฃจํ‹ด์€ ํ•œ ์ค„๋„ ์•ˆ ์ผ๋‹ค")
print(f"[*] ์ตœ์ข… ํ™•์ธ: probe(password) = {probe(known)} / 25")
gdb.execute("quit")
gdb -batch -x oracle_attack.py | grep -E "^\[|^password"

gdb ๋กœ ๋Œ๋ฆฐ ์กฐ๊ธฐ์ข…๋ฃŒ ์˜ค๋ผํด ๊ณต๊ฒฉ โ€” ์ž๋ฆฌ๋งˆ๋‹ค ํ›„๋ณด ๋ฌธ์ž๋ฅผ ๋„ฃ์–ด ์ฒซ ๋ถˆ์ผ์น˜ ์œ„์น˜๊ฐ€ ๋ฐ€๋ฆฌ๋Š”์ง€ ๋ณด๊ณ  ํ•œ ๊ธ€์ž์”ฉ ํ™•์ •ํ•ด 25์ž๋ฆฌ๋ฅผ ์ „๋ถ€ ๋ณต๊ตฌํ•œ๋‹ค. ๋ฐ”์ด๋„ˆ๋ฆฌ๋ฅผ 1046ํšŒ ์‹คํ–‰ํ•˜๋Š” ๋ฐ 95์ดˆ๊ฐ€ ๊ฑธ๋ ธ๊ณ  ๋ณตํ˜ธ ์ฝ”๋“œ๋Š” ์ „ํ˜€ ์“ฐ์ง€ ์•Š์•˜๋‹ค
gdb ๋กœ ๋Œ๋ฆฐ ์กฐ๊ธฐ์ข…๋ฃŒ ์˜ค๋ผํด ๊ณต๊ฒฉ โ€” ์ž๋ฆฌ๋งˆ๋‹ค ํ›„๋ณด ๋ฌธ์ž๋ฅผ ๋„ฃ์–ด ์ฒซ ๋ถˆ์ผ์น˜ ์œ„์น˜๊ฐ€ ๋ฐ€๋ฆฌ๋Š”์ง€ ๋ณด๊ณ  ํ•œ ๊ธ€์ž์”ฉ ํ™•์ •ํ•ด 25์ž๋ฆฌ๋ฅผ ์ „๋ถ€ ๋ณต๊ตฌํ•œ๋‹ค. ๋ฐ”์ด๋„ˆ๋ฆฌ๋ฅผ 1046ํšŒ ์‹คํ–‰ํ•˜๋Š” ๋ฐ 95์ดˆ๊ฐ€ ๊ฑธ๋ ธ๊ณ  ๋ณตํ˜ธ ์ฝ”๋“œ๋Š” ์ „ํ˜€ ์“ฐ์ง€ ์•Š์•˜๋‹ค

๋ฐ”์ด๋„ˆ๋ฆฌ ์‹คํ–‰ 1,046ํšŒ / 95์ดˆ. ๋ณตํ˜ธ ๋ฃจํ‹ด์€ ํ•œ ์ค„๋„ ์•ˆ ์ผ๋Š”๋ฐ ๊ฐ™์€ ๊ฐ’์ด ๋‚˜์™”๋‹ค.

25์ž๋ฆฌ๋ฅผ ์ „์ˆ˜๋กœ ๋’ค์ง€๋ฉด 94^25 ์ธ๋ฐ, ์ž๋ฆฌ๋ณ„๋กœ ์ž˜๋ฆฌ๋‹ˆ 25 ร— 94 ๋กœ ๋–จ์–ด์ง„๋‹ค. ํ™•์‚ฐ์ด ์žˆ์—ˆ๋‹ค๋ฉด ์ด ๊ณต๊ฒฉ์€ ์• ์ดˆ์— ์„ฑ๋ฆฝํ•˜์ง€ ์•Š๋Š”๋‹ค. ํ•œ ๋ฐ”์ดํŠธ๋งŒ ๋ฐ”๊ฟ”๋„ ์•”ํ˜ธ๋ฌธ ์ „์ฒด๊ฐ€ ๋’ค์ง‘ํ˜€์„œ "์•ž์—์„œ ๋ช‡ ๋ฒˆ์งธ๊นŒ์ง€ ๋งž์•˜๋‹ค"๋Š” ๊ฐœ๋… ์ž์ฒด๊ฐ€ ์—†๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

์ •๋ฆฌํ•˜๋ฉด ์ด ๋ฐ”์ด๋„ˆ๋ฆฌ๋Š” ๊ฐ™์€ ๊ธ‰์†Œ๋กœ ๋‘ ๋ฒˆ ์—ด๋ฆฐ๋‹ค.

๊ฒฝ๋กœํ•„์š”ํ•œ ๊ฒƒ๋น„์šฉ
๋ผ์šด๋“œ ์—ญ์‚ฐ.data ์˜ ๋งˆ์Šคํ„ฐํ‚ค์ฆ‰์‹œ
์„ ํƒํ‰๋ฌธ ์ฝ”๋“œ๋ถ์•”ํ˜ธํ™” ์˜ค๋ผํด์งˆ์˜ 256ํšŒ
์กฐ๊ธฐ์ข…๋ฃŒ ์˜ค๋ผํด๊ฒ€์ฆ ๋ฐ”์ด๋„ˆ๋ฆฌ๋งŒ์‹คํ–‰ 1,046ํšŒ ยท 95์ดˆ

์„ธ ๋ฒˆ์งธ๊ฐ€ ์ œ์ผ ๊ณ ์•ฝํ•˜๋‹ค. ํ‚ค๋„ ์•Œ๊ณ ๋ฆฌ์ฆ˜๋„ ๋ชฐ๋ผ๋„ ๋˜๊ณ , ์‹คํ–‰ ํŒŒ์ผ ํ•˜๋‚˜๋งŒ ์žˆ์œผ๋ฉด ๋œ๋‹ค.


๐Ÿš€ ์žฌํ˜„

์ž‘์—… ํด๋”๋งŒ ์žˆ์œผ๋ฉด ์ฒ˜์Œ๋ถ€ํ„ฐ ๋๊นŒ์ง€ ํ•œ ๋ฒˆ์— ๋ˆ๋‹ค.

#!/usr/bin/env bash
# locked present (DreamHack, Silver 1) โ€” ํ•œ ๋ฐฉ ์žฌํ˜„.
#   cipher.py ์žฌ๊ตฌํ˜„์œผ๋กœ .data ์˜ ์•”ํ˜ธ๋ฌธ์„ ๋ณตํ˜ธ โ†’ ๋ฌธ์ œ ๋ฐ”์ด๋„ˆ๋ฆฌ๋กœ ํŒ์ •๊นŒ์ง€.
set -eu
cd "$(dirname "$(readlink -f "$0")")"
 
EXPECT=$(python3 -c "import json;print(json.load(open('๋ฌธ์ œ.json'))['flag'])" 2>/dev/null || echo '')
 
echo "== 1) ์žฌ๊ตฌํ˜„์œผ๋กœ ๋ณตํ˜ธ =="
OUT=$(timeout 120 python3 solve.py 2>&1) || true
echo "$OUT"
FLAG=$(printf '%s' "$OUT" | grep -aoE 'DH\{[^}]+\}' | head -1)
 
echo
echo "== 2) ์žฌ๊ตฌ์„ฑ C ์†Œ์Šค๋กœ ๊ฐ™์€ ์•”ํ˜ธ๋ฌธ์ด ๋‚˜์˜ค๋Š”์ง€ =="
gcc -O0 -no-pie -o recon recon.c
./recon extracted/prob | tail -2
 
echo
echo "== 3) ๋ฌธ์ œ ๋ฐ”์ด๋„ˆ๋ฆฌ์— ์‹ค์ œ ์ž…๋ ฅ =="
chmod +x extracted/prob
python3 verify.py | head -4
 
RC=$(python3 - "$FLAG" <<'PY'
import subprocess, sys
r = subprocess.run(["./extracted/prob"], input=sys.argv[1] + "\n",
                   capture_output=True, text=True)
print(r.returncode)
PY
)
 
echo
if [ -n "$FLAG" ] && [ "$RC" = "0" ] && { [ -z "$EXPECT" ] || [ "$FLAG" = "$EXPECT" ]; }; then
  echo "โœ… PASS  $FLAG"
  exit 0
fi
echo "โŒ FAIL (์–ป์€ ๊ฐ’: '${FLAG:-์—†์Œ}' / ๊ธฐ๋Œ€: '${EXPECT:-๋ฏธ๊ธฐ๋ก}' / ๋ฐ”์ด๋„ˆ๋ฆฌ rc: $RC)"
exit 1
./reproduce.sh

reproduce.sh ์‹คํ–‰ ๊ฒฐ๊ณผ โ€” ์žฌ๊ตฌํ˜„์œผ๋กœ ๋ณตํ˜ธํ•˜๊ณ  ์žฌ๊ตฌ์„ฑ C ์†Œ์Šค๋กœ ์•”ํ˜ธ๋ฌธ์„ ์žฌํ˜„ํ•œ ๋’ค ๋ฌธ์ œ ๋ฐ”์ด๋„ˆ๋ฆฌ์— ์‹ค์ œ๋กœ ์ž…๋ ฅํ•ด correct ๋ฅผ ๋ฐ›๊ณ  ๋งˆ์ง€๋ง‰์— PASS ์™€ ํ”Œ๋ž˜๊ทธ๋ฅผ ์ฐ๋Š”๋‹ค
reproduce.sh ์‹คํ–‰ ๊ฒฐ๊ณผ โ€” ์žฌ๊ตฌํ˜„์œผ๋กœ ๋ณตํ˜ธํ•˜๊ณ  ์žฌ๊ตฌ์„ฑ C ์†Œ์Šค๋กœ ์•”ํ˜ธ๋ฌธ์„ ์žฌํ˜„ํ•œ ๋’ค ๋ฌธ์ œ ๋ฐ”์ด๋„ˆ๋ฆฌ์— ์‹ค์ œ๋กœ ์ž…๋ ฅํ•ด correct ๋ฅผ ๋ฐ›๊ณ  ๋งˆ์ง€๋ง‰์— PASS ์™€ ํ”Œ๋ž˜๊ทธ๋ฅผ ์ฐ๋Š”๋‹ค

๋กœ์ปฌ ํ™˜๊ฒฝ์€ ์ด๋ ‡๋‹ค.

ํ•ญ๋ชฉ๊ฐ’
OSUbuntu ๊ธฐ๋ฐ˜ Linux 6.17 x86-64
gcc9.4.0 ์œผ๋กœ ๋นŒ๋“œ๋œ ๋ฐฐํฌ๋ณธ / ์žฌ๊ตฌ์„ฑ์€ ๋กœ์ปฌ gcc -O0 -no-pie
gdbGNU gdb 16.3 (ํŒŒ์ด์ฌ ํ™•์žฅ ์‚ฌ์šฉ)
python3.13 ยท pycryptodome (๋น„๊ต์šฉ AES-128 ์—๋งŒ ํ•„์š”)
๋Œ€์ƒextracted/prob sha256 065408f1439584c7bd4d37c3e353538241686a358ad442511c5bfbac954cfd25


๐Ÿ“ ๊ฒฐ๋ก 

MixColumns ๋Š” ์žฅ์‹์ด ์•„๋‹ˆ๋‹ค.

์ด ๋ฌธ์ œ์˜ ์•”ํ˜ธ๋Š” ํ‘œ๋ฅผ ํ•˜๋‚˜๋„ ๋Œ€์ถฉ ๋งŒ๋“ค์ง€ ์•Š์•˜๋‹ค. S-box ๋„ Rcon ๋„ ์ง„์งœ AES ๊ฒƒ์„ ๊ทธ๋Œ€๋กœ ์“ด๋‹ค. ๋ผ์šด๋“œ๋„ 10๋ฒˆ ๋ˆ๋‹ค. ๊ทธ๋Ÿฐ๋ฐ ๋ฐ”์ดํŠธ๋ฅผ ์„ž๋Š” ๋‹จ๊ณ„ ํ•˜๋‚˜๊ฐ€ ๋น ์ง€์ž ๋‚จ์€ ๊ฑด ์ž๋ฆฌ๋งˆ๋‹ค ๋…๋ฆฝ์ธ XOR ํ‘œ 25๊ฐœ์˜€๋‹ค. ๋ผ์šด๋“œ๋ฅผ 100๋ฒˆ ๋Œ๋ ค๋„ ๊ฒฐ๊ณผ๋Š” ๊ฐ™๋‹ค. ์—†๋Š” ํ™•์‚ฐ์€ ๋ฐ˜๋ณต์œผ๋กœ ๋งŒ๋“ค์–ด์ง€์ง€ ์•Š๋Š”๋‹ค.

๋ธ”๋ก ํฌ๊ธฐ์™€ ๋ผ์šด๋“œ ์ˆ˜๋ฅผ ๊ฐ™์ด ๋ด์•ผ ํ•œ๋‹ค.

์—ด ํšŒ์ „์ด ํ†ต์งธ๋กœ ์ƒ์‡„๋œ ๊ฑด ์šฐ์—ฐ์ด๋‹ค. ์—ด ๊ธธ์ด๊ฐ€ 5, ๋ผ์šด๋“œ๊ฐ€ 10 ์ด๋ผ 10j โ‰ก 0 (mod 5) ๊ฐ€ ๋๋‹ค. ๋ผ์šด๋“œ๋ฅผ 11 ๋กœ ์žก์•˜์œผ๋ฉด ์ž๋ฆฌ ์ˆœ์—ด์ด ์‚ด์•„ ์žˆ์—ˆ์„ ๊ฒƒ์ด๋‹ค. ๋ฌผ๋ก  ๊ทธ๋ž˜๋„ ๋ฐ”์ดํŠธ๋Š” ์•ˆ ์„ž์ด๋‹ˆ ๊ทผ๋ณธ์€ ๊ทธ๋Œ€๋กœ์ง€๋งŒ, ์ด๋Ÿฐ ์‹์œผ๋กœ ํŒŒ๋ผ๋ฏธํ„ฐ๊ฐ€ ์„œ๋กœ ๋งž๋ฌผ๋ ค ์„ฑ์งˆ์„ ์ฃฝ์ด๋Š” ์ผ์€ ์ž์ž‘ ์•”ํ˜ธ์—์„œ ํ”ํ•˜๋‹ค.

"ํ‹€๋ ค๋„ ํ‹ฐ๊ฐ€ ์•ˆ ๋‚œ๋‹ค"๊ฐ€ ์ด ๋ฌธ์ œ์˜ ๋‚œ์ด๋„๋‹ค.

ํ‚ค ํ™•์žฅ์˜ ์‹œ์ž‘ ์›Œ๋“œ, Rcon ์„ ๋ช‡ ๋ฐ”์ดํŠธ์— ๋„ฃ๋Š”์ง€, ํšŒ์ „ ๋ฐฉํ–ฅ, ํ–‰์ด๋ƒ ์—ด์ด๋ƒ โ€” ๋„ค ๊ตฐ๋ฐ๋ฅผ ์ž˜๋ชป ์ฝ์–ด๋„ ์˜ˆ์™ธ ํ•˜๋‚˜ ์•ˆ ๋‚˜๊ณ  25๋ฐ”์ดํŠธ๊ฐ€ ๋‚˜์˜จ๋‹ค. ๊ฒฐ๊ตญ ํŒ์ •์€ ์žฌ์•”ํ˜ธํ™” ๊ฒฐ๊ณผ๊ฐ€ .data ์™€ ๊ฐ™์€์ง€, gdb ๋กœ ๋œฌ ์‹ค์ œ ๋ผ์šด๋“œ ์ƒํƒœ์™€ ๋งž๋Š”์ง€, ๋ฌธ์ œ ๋ฐ”์ด๋„ˆ๋ฆฌ๊ฐ€ correct ๋ฅผ ๋ฑ‰๋Š”์ง€๋กœ๋งŒ ํ•  ์ˆ˜ ์žˆ๋‹ค. ์ž์ž‘ ์•”ํ˜ธ๋ฅผ ๋˜๊ฐ์„ ๋•Œ๋Š” ๊ฒ€์ฆ์„ ๋จผ์ € ์„ค๊ณ„ํ•ด ๋‘๋Š” ๊ฒŒ ๋‚ซ๋‹ค.

๊ฒ€์ฆ ๋กœ์ง์—์„œ๋„ ์ •๋ณด๊ฐ€ ์ƒŒ๋‹ค.

์•”ํ˜ธ๋ฅผ ์•„๋ฌด๋ฆฌ ์ž˜ ๋งŒ๋“ค์–ด๋„ ๋น„๊ต๋ฅผ ์ฒซ ๋ถˆ์ผ์น˜์—์„œ ๋Š์œผ๋ฉด ์ž๋ฆฌ๋ณ„ ์˜ค๋ผํด์ด ์ƒ๊ธด๋‹ค. ์—ฌ๊ธฐ์„œ๋Š” ํ™•์‚ฐ์ด 0 ์ด๋ผ ๊ทธ๊ฒŒ ๊ณง๋ฐ”๋กœ ์ „์ฒด ๋ณต๊ตฌ๋กœ ์ด์–ด์กŒ์ง€๋งŒ, ํ™•์‚ฐ์ด ๋ฉ€์ฉกํ•œ ์•”ํ˜ธ๋ผ๋„ ์ด๋Ÿฐ ์กฐ๊ธฐ์ข…๋ฃŒ๋Š” HMAC ๊ฒ€์ฆ ๊ฐ™์€ ๋ฐ์„œ ์‹ค์ œ ๋ฌธ์ œ๊ฐ€ ๋œ๋‹ค. ์ƒ์ˆ˜ ์‹œ๊ฐ„ ๋น„๊ต๋ฅผ ์“ฐ๋Š” ์ด์œ ๊ฐ€ ์ด๊ฒƒ์ด๋‹ค.

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

Comments

๋Œ“๊ธ€

0๊ฐœ

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

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

Related

๊ด€๋ จ ๊ธ€

3๊ฐœ
[๐Ÿฅ‡ 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 +5
[๐Ÿฅˆ Silver 4] addยทrotateยทxor ๋ธ”๋ก์•”ํ˜ธ๋ฅผ ์ •์  ์—ญ์‚ฐ โ€” DreamHack My ARX Cipher ํ’€์ด
blog

[๐Ÿฅˆ Silver 4] addยทrotateยทxor ๋ธ”๋ก์•”ํ˜ธ๋ฅผ ์ •์  ์—ญ์‚ฐ โ€” DreamHack My ARX Cipher ํ’€์ด

stripped ELF ํ•˜๋‚˜๊ฐ€ 12๋ฐ”์ดํŠธ key๋กœ flag.enc๋ฅผ ๋งŒ๋“ค์–ด ๋†“์•˜๋‹ค. ๋ธ”๋ก ํ•จ์ˆ˜๋ฅผ objdump๋กœ ๋œฏ์–ด 4๋ฐ”์ดํŠธ(16bit ์›Œ๋“œ v0ยทv1)์— rotate-add-xor-swap์„ 3๋ผ์šด๋“œ ๋„๋Š” ARX ๊ตฌ์กฐ์ž„์„ ๋ฐํžˆ๊ณ , ๊ฐ ์—ฐ์‚ฐ์„ ์—ญ์œผ๋กœ ๋˜๊ฐ์•„ flag๋ฅผ ๋ณต์›ํ•œ๋‹ค. gdb ๋Ÿฐํƒ€์ž„๊ณผ ์žฌ์•”ํ˜ธํ™” ๋ผ์šด๋“œํŠธ๋ฆฝ์œผ๋กœ ์ด์ค‘ ๊ฒ€์ฆ.
#dreamhack#ctf#reversing+5
2026-07-15#dreamhack +4
[๐Ÿฅˆ Silver 3] 2MB ๋ฐ”์ด๋„ˆ๋ฆฌ์—์„œ ์ฝ”๋“œ๋Š” 509๋ฐ”์ดํŠธ๋ฟ์ด์—ˆ๋‹ค โ€” DreamHack Branches and Leaves ํ’€์ด
blog

[๐Ÿฅˆ Silver 3] 2MB ๋ฐ”์ด๋„ˆ๋ฆฌ์—์„œ ์ฝ”๋“œ๋Š” 509๋ฐ”์ดํŠธ๋ฟ์ด์—ˆ๋‹ค โ€” DreamHack Branches and Leaves ํ’€์ด

๋ฌธ์ œ ์„ค๋ช…์ด ์‹œ ๋„ค ์ค„๋ฟ์ธ ๋ฆฌ๋ฒ„์‹ฑ. 2.1MB์งœ๋ฆฌ stripped ELF๋ฅผ ์—ด์–ด ๋ณด๋ฉด ์ฝ”๋“œ๋Š” 509๋ฐ”์ดํŠธ๊ณ  ๋‚˜๋จธ์ง€ ์ „๋ถ€๊ฐ€ ๋ฐฐ์—ด๋กœ ์ ‘์€ ๊นŠ์ด 16 ์ด์ง„ํŠธ๋ฆฌ๋‹ค. ์ž…๋ ฅ 4๊ธ€์ž๊ฐ€ 16๋น„ํŠธ๋กœ ํŽด์ ธ ํŠธ๋ฆฌ๋ฅผ 16๋ฒˆ ๋‚ด๋ ค๊ฐ€๊ณ , ๊ทธ ๋ฆฌํ”„ 65536๊ฐœ๊ฐ€ ์„œ๋กœ ๊ฒน์น˜์ง€ ์•Š์•„์„œ ๊ธฐ๋Œ€๊ฐ’๋งˆ๋‹ค ์—ญ์ƒ์ด ์ •ํ™•ํžˆ ํ•˜๋‚˜๋กœ ์ •ํ•ด์ง„๋‹ค.
#dreamhack#ctf#reversing+5
2026-08-19#dreamhack +4