[๐Ÿฅˆ Silver 1] ํ‚ค์ŠคํŠธ๋ฆผ 1๋น„ํŠธ๋กœ ๋˜๋Œ๋ฆฐ SNOW 3G โ€” DreamHack snow ํ’€์ด

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

[๐Ÿฅˆ Silver 1] ํ‚ค์ŠคํŠธ๋ฆผ 1๋น„ํŠธ๋กœ ๋˜๋Œ๋ฆฐ SNOW 3G โ€” DreamHack snow ํ’€์ด

20KB ์งœ๋ฆฌ ์ŠคํŠธ๋ฆฝํŠธ ELF ์•ˆ์— 3GPP ํ‘œ์ค€ ์ŠคํŠธ๋ฆผ ์•”ํ˜ธ SNOW 3G ๊ฐ€ ํ†ต์งธ๋กœ ๋“ค์–ด ์žˆ์—ˆ๋‹ค. ํ‚ค๋Š” "Merry-Christmas!" ๋กœ ๊ณ ์ •์ด๊ณ  IV ๋Š” ์šฐ๋ฆฌ๊ฐ€ ๋„ฃ๋Š” ์ž…๋ ฅ์˜ ์•ž 16๋ฐ”์ดํŠธ โ€” ์ฆ‰ ๋ณต์›ํ•ด์•ผ ํ•  ๊ฐ’์ด ์ž๊ธฐ ์ž์‹ ์„ ์•”ํ˜ธํ™”ํ•œ๋‹ค. ์›Œ๋“œ๋งˆ๋‹ค ํ•„์š”ํ•œ ์ •๋ณด๊ฐ€ ํ‚ค์ŠคํŠธ๋ฆผ์˜ ์ตœํ•˜์œ„ 1๋น„ํŠธ๋ฟ์ด๋ผ๋Š” ์ ์„ ์ด์šฉํ•ด 256๊ฐ€์ง€๋งŒ ํ™•์ธํ•˜๊ณ  32๊ธ€์ž๋ฅผ ๋˜๋Œ๋ ธ๋‹ค.

๋ฌธ์ œ: DreamHack โ€” snow ๋ถ„๋ฅ˜: reversing ๋‚œ์ด๋„: ๐Ÿฅˆ Silver 1 FLAG: DH{F805042AC5E59FD07ABEF1E9B2EF}

๋ฌธ์ œ ์„ค๋ช…์€ ๋”ฑ ํ•œ ์ค„, "๋ˆˆ์ด ๋ ์šฉ~" ์ด๋‹ค. ํžŒํŠธ๋„ ์—†๊ณ  ์ฒจ๋ถ€๋Š” prob ํ•˜๋‚˜๋ฟ์ด๋‹ค. ์šฐ์„  ์–ด๋–ค ํŒŒ์ผ์ธ์ง€๋ถ€ํ„ฐ ๋ดค๋‹ค.

file prob && readelf -h -d prob | grep -E "Type:|Entry|NEEDED|BIND_NOW|FLAGS" && objdump -T prob | grep -E "strcpy|memcmp|strlen|printf"

file ๊ณผ readelf ๋กœ ํ™•์ธํ•œ prob ์˜ ๊ธฐ๋ณธ ์ •๋ณด โ€” ์ŠคํŠธ๋ฆฝํŠธ๋œ PIE ELF ์ด๊ณ  import ๋Š” strcpy strlen printf memcmp ๋ฟ์ด๋‹ค
file ๊ณผ readelf ๋กœ ํ™•์ธํ•œ prob ์˜ ๊ธฐ๋ณธ ์ •๋ณด โ€” ์ŠคํŠธ๋ฆฝํŠธ๋œ PIE ELF ์ด๊ณ  import ๋Š” strcpy strlen printf memcmp ๋ฟ์ด๋‹ค

์ œ๋ชฉ์ด ๋ˆˆ(snow)์ด๋ผ ์ฒซ์ธ์ƒ์€ ํฌ๋ฆฌ์Šค๋งˆ์Šค ๋†๋‹ด ๊ฐ™์•˜๋Š”๋ฐ, ์‹ค์ œ๋กœ๋Š” ์ด๋ฆ„์ด ๊ทธ๋Œ€๋กœ ๋‹ต์ด์—ˆ๋‹ค.


๋ฌธ์ œ ๊ฐœ์š”

ํ•ญ๋ชฉ๋‚ด์šฉ
๋ฌธ์ œ๋ช…snow
๋‚œ์ด๋„๐Ÿฅˆ Silver 1
๋ถ„๋ฅ˜reversing
์ œ๊ณต ํŒŒ์ผprob (x86-64 PIE ELF, stripped, 16,568 bytes)
์„œ๋ฒ„์—†์Œ โ€” ์˜คํ”„๋ผ์ธ ๋ฌธ์ œ
ํ•ต์‹ฌ ๊ธฐ๋ฒ•SNOW 3G ์žฌ๊ตฌํ˜„ + ์ž๊ธฐ์ฐธ์กฐ IV ๋ฅผ 8๋น„ํŠธ ํƒ์ƒ‰์œผ๋กœ ์ ‘๊ธฐ

ํ๋ฆ„์€ ์ด๋ ‡๋‹ค. ๋ฐ”์ด๋„ˆ๋ฆฌ๋Š” 32๊ธ€์ž์งœ๋ฆฌ ์ธ์ž๋ฅผ ๋ฐ›์•„ ์–ด๋–ค ๋ณ€ํ™˜์„ ๊ฑฐ์นœ ๋’ค .data ์— ๋ฐ•ํžŒ 32๋ฐ”์ดํŠธ์™€ memcmp ํ•œ๋‹ค.

๊ทธ ๋ณ€ํ™˜์— ์“ฐ์ด๋Š” ๋‚œ์ˆ˜๋Š” 3GPP ํ‘œ์ค€ ์ŠคํŠธ๋ฆผ ์•”ํ˜ธ SNOW 3G ์˜ ํ‚ค์ŠคํŠธ๋ฆผ์ด๊ณ , ํ‚ค๋Š” ์†Œ์Šค์— ๋ฐ•ํ˜€ ์žˆ๋‹ค.

๋ฌธ์ œ๋Š” IV ๊ฐ€ ์šฐ๋ฆฌ ์ž…๋ ฅ์˜ ์•ž 16๋ฐ”์ดํŠธ๋ผ๋Š” ๊ฒƒ. ๋ณต์›ํ•˜๋ ค๋Š” ๊ฐ’์ด ์ž๊ธฐ ์ž์‹ ์˜ ์•”ํ˜ธํ™”์— ๊ด€์—ฌํ•œ๋‹ค.



๐Ÿงฉ ๋ฐฐ๊ฒฝ โ€” LFSR ํ•˜๋‚˜๋กœ ๋‚œ์ˆ˜๋ฅผ ๋งŒ๋“ ๋‹ค๋Š” ๊ฒƒ

์ŠคํŠธ๋ฆผ ์•”ํ˜ธ๋Š” ํ‚ค์™€ IV ๋กœ ๊ธด ๋‚œ์ˆ˜์—ด(ํ‚ค์ŠคํŠธ๋ฆผ)์„ ๋ฝ‘์•„ ํ‰๋ฌธ์— XOR ํ•˜๋Š” ๋ฐฉ์‹์ด๋‹ค. ๊ทธ ๋‚œ์ˆ˜์—ด์˜ ๋ผˆ๋Œ€๋กœ ๊ฐ€์žฅ ์˜ค๋ž˜ ์“ฐ์ธ ๊ฒŒ ์„ ํ˜• ๋˜๋จน์ž„ ์‹œํ”„ํŠธ ๋ ˆ์ง€์Šคํ„ฐ(LFSR)๋‹ค.

๋ ˆ์ง€์Šคํ„ฐ๋ฅผ ํ•œ ์นธ์”ฉ ๋ฐ€๋ฉด์„œ, ๋ฐ€๋ ค๋‚˜๋Š” ์ž๋ฆฌ์—๋Š” ์ •ํ•ด์ง„ ๋ช‡ ๊ฐœ ์ž๋ฆฌ๋ฅผ XOR ํ•œ ๊ฐ’์„ ์ฑ„์›Œ ๋„ฃ๋Š”๋‹ค. ๊ทธ๋ฆผ์œผ๋กœ ๋ณด๋ฉด ํ•œ๋ˆˆ์— ๋“ค์–ด์˜จ๋‹ค.

Wikimedia Commons ์˜ 16๋น„ํŠธ ํ”ผ๋ณด๋‚˜์น˜ LFSR ๋„์‹ โ€” 11 13 14 16๋ฒˆ ํƒญ์„ XOR ํ•ด ์™ผ์ชฝ ๋์œผ๋กœ ๋˜๋จน์ธ๋‹ค
Wikimedia Commons ์˜ 16๋น„ํŠธ ํ”ผ๋ณด๋‚˜์น˜ LFSR ๋„์‹ โ€” 11 13 14 16๋ฒˆ ํƒญ์„ XOR ํ•ด ์™ผ์ชฝ ๋์œผ๋กœ ๋˜๋จน์ธ๋‹ค

์ถœ์ฒ˜: Wikimedia Commons, KCAuXy4p, CC0

LFSR ๋งŒ ์“ฐ๋ฉด ์ฃผ๊ธฐ๋Š” ๊ธธ์ง€๋งŒ ์„ ํ˜•์ด๋ผ ๊ทธ๋Œ€๋กœ๋Š” ์•ˆ์ „ํ•˜์ง€ ์•Š๋‹ค. ๊ทธ๋ž˜์„œ SNOW ๊ณ„์—ด์€ LFSR ์œ„์— ๋น„์„ ํ˜• ์œ ํ•œ์ƒํƒœ๊ธฐ๊ณ„(FSM)๋ฅผ ์–น๋Š”๋‹ค.

LFSR ์€ 32๋น„ํŠธ ์›Œ๋“œ 16๊ฐœ(s0~s15)๋กœ ๋˜์–ด ์žˆ๊ณ , FSM ์€ 32๋น„ํŠธ ๋ ˆ์ง€์Šคํ„ฐ ์„ธ ๊ฐœ(R1, R2, R3)๋ฅผ ๊ตด๋ฆฐ๋‹ค. SNOW 3G ๋Š” ์ด ๊ตฌ์กฐ๋กœ 3GPP ์˜ UEA2/UIA2 โ€” LTE ์˜ ์•”ํ˜ธํ™”ยท๋ฌด๊ฒฐ์„ฑ ์•Œ๊ณ ๋ฆฌ์ฆ˜ โ€” ์— ๋“ค์–ด๊ฐ€ ์žˆ๋Š” ํ‘œ์ค€์ด๋‹ค.

์ด ๋ฌธ์ œ์˜ ๋ฐ”์ด๋„ˆ๋ฆฌ๊ฐ€ ํ†ต์งธ๋กœ ๊ทธ ๊ตฌ์กฐ๋‹ค.

์ง์ ‘ ๊ทธ๋ฆฐ SNOW 3G ๊ตฌ์กฐ๋„ โ€” LFSR 16์›Œ๋“œ์—์„œ s0 s2 s11 ์„ ๋˜๋จน์ด๊ณ  FSM ์ด s5 ์™€ s15 ๋ฅผ ๋ฐ›์•„ z ๋ฅผ ๋‚ธ๋‹ค
์ง์ ‘ ๊ทธ๋ฆฐ SNOW 3G ๊ตฌ์กฐ๋„ โ€” LFSR 16์›Œ๋“œ์—์„œ s0 s2 s11 ์„ ๋˜๋จน์ด๊ณ  FSM ์ด s5 ์™€ s15 ๋ฅผ ๋ฐ›์•„ z ๋ฅผ ๋‚ธ๋‹ค

์—ฌ๊ธฐ์„œ ์šฐ๋ฆฌ๊ฐ€ ์“ธ ์ถœ๋ ฅ์€ ๋งจ ์™ผ์ชฝ ์ƒ์ž๋‹ค. 32๋น„ํŠธ ์›Œ๋“œ z ๊ฐ€ ๋‚˜์˜ค๋Š”๋ฐ, ๋ฌธ์ œ๋Š” ๊ทธ ์ค‘ ์ตœํ•˜์œ„ 1๋น„ํŠธ๋งŒ ์“ด๋‹ค. ์ด ๋‚ญ๋น„๊ฐ€ ๊ณง ํ’€์ด์˜ ์—ด์‡ ์˜€๋‹ค.



๐Ÿ”ฌ ์ •์ฐฐ โ€” ์‹ฌ๋ณผ์ด ํ•˜๋‚˜๋„ ์—†๋‹ค

file ๊ฒฐ๊ณผ๋Œ€๋กœ stripped PIE ๋‹ค. import ๋ชฉ๋ก์ด ์งง์•„์„œ ์˜คํžˆ๋ ค ์–˜๊ธฐ๊ฐ€ ๋นจ๋ž๋‹ค. strcpy, strlen, printf, puts, memcmp, exit, __stack_chk_fail. ํŒŒ์ผ ์ž…์ถœ๋ ฅ๋„ ๋„คํŠธ์›Œํฌ๋„ ์—†๋‹ค. ์ธ์ž ํ•˜๋‚˜ ๋ฐ›์•„์„œ ๊ณ„์‚ฐํ•˜๊ณ  ๋น„๊ตํ•˜๋Š” ๊ฒŒ ์ „๋ถ€๋ผ๋Š” ๋œป์ด๋‹ค.

๋ฌธ์ž์—ด์„ ๋ณด๋ฉด ๋” ๋ถ„๋ช…ํ•ด์ง„๋‹ค.

strings -a -t x prob | grep -E "Merr|y-Ch|rist|mas|usage:|length of|Correct|Wrong"

strings ์ถœ๋ ฅ โ€” mas! rist y-Ch Merr ๋„ค ์กฐ๊ฐ์ด 0x1af2 ๋ถ€ํ„ฐ 7๋ฐ”์ดํŠธ ๊ฐ„๊ฒฉ์œผ๋กœ ์ด์–ด์ ธ ๋‚˜์˜จ๋‹ค
strings ์ถœ๋ ฅ โ€” mas! rist y-Ch Merr ๋„ค ์กฐ๊ฐ์ด 0x1af2 ๋ถ€ํ„ฐ 7๋ฐ”์ดํŠธ ๊ฐ„๊ฒฉ์œผ๋กœ ์ด์–ด์ ธ ๋‚˜์˜จ๋‹ค

usage: %s <string>, length of string must be 32., Correct!, Wrong... ์€ ์˜ˆ์ƒ๋Œ€๋กœ๋‹ค.

๋ˆˆ์— ๊ฑธ๋ฆฌ๋Š” ๊ฑด ์œ„์ชฝ ๋„ค ์ค„์ด๋‹ค. mas!, rist, y-Ch, Merr. ๋ถ™์—ฌ ์ฝ์œผ๋ฉด Merry-Christmas! ์ด๊ณ , ์กฐ๊ฐ์ด ๋”ฑ 4๋ฐ”์ดํŠธ์”ฉ ๋Š๊ฒจ ์žˆ๋‹ค.

๊ทธ๋ฆฌ๊ณ  ์˜คํ”„์…‹์ด .rodata(0x2000๋Œ€)๊ฐ€ ์•„๋‹ˆ๋ผ .text ํ•œ๋ณตํŒ์ธ 0x1af2 ๋ถ€ํ„ฐ 7๋ฐ”์ดํŠธ ๊ฐ„๊ฒฉ์ด๋‹ค. mov DWORD PTR [rbp-N], imm32 ๋ช…๋ น์˜ ์ฆ‰์น˜๊ฐ’ ์ž๋ฆฌ๋ผ๋Š” ๋œป์ด๋‹ค. ๋ฌธ์ž์—ด ์ƒ์ˆ˜๊ฐ€ ์•„๋‹ˆ๋ผ ์ฝ”๋“œ์— ๋ฐ•ํžŒ 32๋น„ํŠธ ์ •์ˆ˜ ๋„ค ๊ฐœ๋‹ค.

32๋น„ํŠธ ์›Œ๋“œ ๋„ค ๊ฐœ = 128๋น„ํŠธ. ๊ทธ๋ฆฌ๊ณ  ๋ฌธ์ œ ์ด๋ฆ„์€ snow. ์ด์ฏค์—์„œ SNOW 3G ๋ฅผ ์˜์‹ฌํ•˜๊ณ  ๋””์Šค์–ด์…ˆ๋ธ”๋กœ ๋“ค์–ด๊ฐ”๋‹ค.


๐Ÿงฑ ๊ฐˆ๋ฃจ์•„์ฒด ๊ณฑ์…ˆ โ€” ๊ฐ€์žฅ ์•ˆ์ชฝ๋ถ€ํ„ฐ

objdump ๋กœ ํ›‘์œผ๋ฉด ํ•จ์ˆ˜ ๊ฒฝ๊ณ„๊ฐ€ endbr64 + push rbp ๋กœ ๊น”๋”ํ•˜๊ฒŒ ์žกํžŒ๋‹ค. ๊ฐ€์žฅ ์•ˆ์ชฝ์— ์žˆ๋Š” 0x1209 ๋ถ€ํ„ฐ ๋ดค๋‹ค.

์ฃผ์„์„ ์–น๊ธฐ ์œ„ํ•ด ์น˜ํ™˜ ๊ทœ์น™์„ ํŒŒ์ผ๋กœ ๋งŒ๋“ค์–ด ๋’€๋‹ค. --cmd ์•ˆ์— sed 's|...|...|' ๋ฅผ ์ธ๋ผ์ธ์œผ๋กœ ๋„ฃ์œผ๋ฉด ๋”ฐ์˜ดํ‘œ๊ฐ€ ๊นจ์ง€๋ฏ€๋กœ -f ๋กœ ๋ถ€๋ฅด๋Š” ํŽธ์ด ์•ˆ์ „ํ•˜๋‹ค.

# annot_mulx.sed
s|(c1 e8 07.*shr +eax,0x7)$|\1        <-- V ์˜ ์ตœ์ƒ์œ„ ๋น„ํŠธ๋ฅผ ๋ฝ‘๋Š”๋‹ค|
s|(83 e0 01.*and +eax,0x1)$|\1        <-- MSB ๋งŒ ๋‚จ๊ธด๋‹ค|
s|(83 7d fc 01.*cmp +DWORD PTR \[rbp-0x4\],0x1)$|\1   <-- MSB ๊ฐ€ 1์ด๋ฉด ๊ฐ์‚ฐ์ด ํ•„์š”|
s|(01 c0.*add +eax,eax)$|\1        <-- V << 1|
s|(33 45 e8.*xor +eax,DWORD PTR \[rbp-0x18\])$|\1   <-- ^ c : ๊ธฐ์•ฝ๋‹คํ•ญ์‹์œผ๋กœ ์ ‘๋Š”๋‹ค|
objdump -d -M intel --start-address=0x1209 --stop-address=0x1240 prob | sed -E -f annot_mulx.sed

objdump ๋กœ ๋ฝ‘์€ 0x1209 ํ•จ์ˆ˜ โ€” ์ตœ์ƒ์œ„ ๋น„ํŠธ๋ฅผ ๊ฒ€์‚ฌํ•ด ์™ผ์ชฝ ์‹œํ”„ํŠธ ํ›„ ์กฐ๊ฑด๋ถ€๋กœ ์ƒ์ˆ˜๋ฅผ XOR ํ•˜๋Š” MULx ๋‹ค
objdump ๋กœ ๋ฝ‘์€ 0x1209 ํ•จ์ˆ˜ โ€” ์ตœ์ƒ์œ„ ๋น„ํŠธ๋ฅผ ๊ฒ€์‚ฌํ•ด ์™ผ์ชฝ ์‹œํ”„ํŠธ ํ›„ ์กฐ๊ฑด๋ถ€๋กœ ์ƒ์ˆ˜๋ฅผ XOR ํ•˜๋Š” MULx ๋‹ค

์ฝ์–ด ๋ณด๋ฉด ์ด๋Ÿฐ ํ•จ์ˆ˜๋‹ค.

uint8_t MULx(uint8_t V, uint8_t c) {
    if (V & 0x80) return ((V << 1) & 0xff) ^ c;
    else          return  (V << 1) & 0xff;
}

GF(2^8) ์—์„œ x ๋ฅผ ๊ณฑํ•˜๋Š” ์—ฐ์‚ฐ, ํ”ํžˆ xtime ์ด๋ผ ๋ถ€๋ฅด๋Š” ๊ฒƒ์ด๋‹ค. ๋‹ค๋งŒ ๊ธฐ์•ฝ๋‹คํ•ญ์‹ ์ƒ์ˆ˜ c ๊ฐ€ ํ•˜๋“œ์ฝ”๋”ฉ์ด ์•„๋‹ˆ๋ผ ์ธ์ž๋กœ ๋“ค์–ด์˜จ๋‹ค. AES ๊ตฌํ˜„์ด๋ผ๋ฉด 0x1b ๊ฐ€ ์ฝ”๋“œ์— ๋ฐ•ํ˜€ ์žˆ์—ˆ์„ ํ…๋ฐ ๊ทธ๋ ‡์ง€ ์•Š๋‹ค๋Š” ๊ฒŒ ์ฒซ ๋ฒˆ์งธ ๋‹จ์„œ์˜€๋‹ค.

๋ฐ”๋กœ ๋’ค 0x1240 ์€ ์ด ํ•จ์ˆ˜๋ฅผ i ๋ฒˆ ์žฌ๊ท€ ํ˜ธ์ถœํ•œ๋‹ค. i == 0 ์ด๋ฉด ๊ทธ๋Œ€๋กœ ๋ฐ˜ํ™˜ํ•˜๊ณ , ์•„๋‹ˆ๋ฉด MULx(MULxPOW(V, i-1, c), c). SNOW 3G ๋ช…์„ธ์˜ MULxPOW(V, i, c) ๊ทธ๋Œ€๋กœ๋‹ค.

์ด ๋‘ ํ•จ์ˆ˜๊ฐ€ ์•„๋ž˜ ๋‚˜์˜ค๋Š” ๋ชจ๋“  ๊ฒƒ์˜ ๋ถ€ํ’ˆ์ด ๋œ๋‹ค.



๐Ÿ’ฃ ์ƒ์ž ๋‘ ๊ฐœ โ€” S1 ๊ณผ S2

0x128b ๊ณผ 0x1530 ์€ ๊ตฌ์กฐ๊ฐ€ ๋˜‘๊ฐ™๊ณ  ์ฐธ์กฐํ•˜๋Š” ํ…Œ์ด๋ธ”๊ณผ ์ƒ์ˆ˜๋งŒ ๋‹ค๋ฅด๋‹ค. 32๋น„ํŠธ ์›Œ๋“œ๋ฅผ ๋ฐ”์ดํŠธ ๋„ท์œผ๋กœ ์ชผ๊ฐœ๊ณ , ๊ฐ ๋ฐ”์ดํŠธ๋กœ 256์—”ํŠธ๋ฆฌ ํ…Œ์ด๋ธ”์„ ์กฐํšŒํ•œ ๋’ค, ๊ฒฐ๊ณผ ๋„ท์„ GF ๊ณฑ์…ˆ๊ณผ XOR ๋กœ ์„ž์–ด ๋‹ค์‹œ 32๋น„ํŠธ๋กœ ํ•ฉ์นœ๋‹ค.

์ฒซ ๋ฒˆ์งธ ํ–‰์ด ์–ด๋–ป๊ฒŒ ๋งŒ๋“ค์–ด์ง€๋Š”์ง€ ๋ณด์ž.

objdump -d -M intel --start-address=0x12c9 --stop-address=0x135b prob | sed -E -f annot_s1.sed

objdump ๋กœ ๋ณธ S1 ์˜ ์ฒซ ํ–‰ ๊ณ„์‚ฐ โ€” 0x4020 ํ…Œ์ด๋ธ”์„ ๋„ค ๋ฒˆ ์กฐํšŒํ•˜๊ณ  0x1b ๋กœ MULx ๋ฅผ ๋‘ ๋ฒˆ ๋ถ€๋ฅธ๋‹ค
objdump ๋กœ ๋ณธ S1 ์˜ ์ฒซ ํ–‰ ๊ณ„์‚ฐ โ€” 0x4020 ํ…Œ์ด๋ธ”์„ ๋„ค ๋ฒˆ ์กฐํšŒํ•˜๊ณ  0x1b ๋กœ MULx ๋ฅผ ๋‘ ๋ฒˆ ๋ถ€๋ฅธ๋‹ค

์ •๋ฆฌํ•˜๋ฉด r0 = 2ยทT[b0] ^ T[b1] ^ T[b2] ^ 3ยทT[b3] ์ด๋‹ค. ๋‚˜๋จธ์ง€ ์„ธ ํ–‰๋„ ๊ฐ™์€ ๊ณ„์ˆ˜๋ฅผ ํ•œ ์นธ์”ฉ ๋Œ๋ ค ์“ด๋‹ค.

โ–ถ๐Ÿ› ์‚ฝ์งˆ 1 โ€” ์ด๊ฑธ AES MixColumns ๋กœ ์ฝ์—ˆ๋‹ค

๊ณ„์ˆ˜๊ฐ€ 2์™€ 3์œผ๋กœ๋งŒ ์ด๋ฃจ์–ด์ง„ 4x4 ์ˆœํ™˜ํ–‰๋ ฌ์— ํ…Œ์ด๋ธ”์ด AES S-box๋ผ๋ฉด, ๋ฐ˜์‚ฌ์ ์œผ๋กœ MixColumns๋ฅผ ๋– ์˜ฌ๋ฆฌ๊ฒŒ ๋œ๋‹ค. ์‹ค์ œ๋กœ ๋‚˜๋„ ์ฒ˜์Œ์—” "AES ๋ผ์šด๋“œ ํ•˜๋‚˜๋ฅผ ์†์œผ๋กœ ํŽธ ๊ฒƒ"์œผ๋กœ ์ฝ์—ˆ๋‹ค.

๊ทธ๋Ÿฐ๋ฐ AES MixColumns ์˜ ์ฒซ ํ–‰์€ (2, 3, 1, 1) ์ด๋‹ค. ์—ฌ๊ธฐ ๋‚˜์˜จ ๊ฑด (2, 1, 1, 3) ์ด๋‹ค. ๋‘˜์€ ์„œ๋กœ ์ „์น˜ ๊ด€๊ณ„๋ผ์„œ ๊ฒ‰๋ณด๊ธฐ ์ธ์ƒ์ด ๊ฑฐ์˜ ๊ฐ™๊ณ , ๊ทธ๋ž˜์„œ ๋” ํ—ท๊ฐˆ๋ฆฐ๋‹ค.

๊ณ„์ˆ˜๋งŒ AES ์ชฝ์œผ๋กœ ๋ฐ”๊ฟ” ๋‘๊ณ  ๋˜‘๊ฐ™์€ ํƒ์ƒ‰์„ ๋Œ๋ ค ๋ดค๋‹ค.

# sapjil_mixcolumns.py โ€” ๊ณ„์ˆ˜๋ฅผ AES MixColumns ๋กœ ๋ฐ”๊ฟจ์„ ๋•Œ
class MixColumnsBox(Snow3G):
    def _box(self, w, T, c):
        w0, w1, w2, w3 = (w >> 24) & 0xFF, (w >> 16) & 0xFF, (w >> 8) & 0xFF, w & 0xFF
        t0, t1, t2, t3 = T[w0], T[w1], T[w2], T[w3]
        m = lambda v: self.MULx(v, c)
        # AES MixColumns: ๊ฐ ํ–‰์ด (2,3,1,1) ์„ ํ•œ ์นธ์”ฉ ๋Œ๋ ค ์“ด๋‹ค
        r0 = m(t0) ^ (m(t1) ^ t1) ^ t2 ^ t3
        r1 = t0 ^ m(t1) ^ (m(t2) ^ t2) ^ t3
        r2 = t0 ^ t1 ^ m(t2) ^ (m(t3) ^ t3)
        r3 = (m(t0) ^ t0) ^ t1 ^ t2 ^ m(t3)
        return ((r0 << 24) | (r1 << 16) | (r2 << 8) | r3) & snow3g.M32
python3 sapjil_mixcolumns.py

MixColumns ๊ณ„์ˆ˜๋กœ ๋ฐ”๊ฟ” ๋Œ๋ฆฐ ๊ฒฐ๊ณผ โ€” 256๊ฐ€์ง€ ๊ฐ€์ • ์ค‘ ์ž๊ธฐ๋ฌด๋ชจ์ˆœ์œผ๋กœ ์‚ด์•„๋‚จ๋Š” ํ›„๋ณด๊ฐ€ ํ•˜๋‚˜๋„ ์—†๋‹ค
MixColumns ๊ณ„์ˆ˜๋กœ ๋ฐ”๊ฟ” ๋Œ๋ฆฐ ๊ฒฐ๊ณผ โ€” 256๊ฐ€์ง€ ๊ฐ€์ • ์ค‘ ์ž๊ธฐ๋ฌด๋ชจ์ˆœ์œผ๋กœ ์‚ด์•„๋‚จ๋Š” ํ›„๋ณด๊ฐ€ ํ•˜๋‚˜๋„ ์—†๋‹ค

ํ›„๋ณด 0๊ฐœ. ์ด ๋ฌธ์ œ๋Š” ๋‹ต์ด ๋งž์•˜๋Š”์ง€ ํ‹€๋ ธ๋Š”์ง€๋ฅผ ์•Œ๋ ค ์ฃผ๋Š” ์‹ ํ˜ธ๊ฐ€ ๋งˆ์ง€๋ง‰ memcmp ํ•˜๋‚˜๋ฟ์ด๋ผ, ์ค‘๊ฐ„์— ํ•œ ๊ธ€์ž๋ผ๋„ ์–ด๊ธ‹๋‚˜๋ฉด ์ด๋ ‡๊ฒŒ ์ „๋ฉธํ•œ๋‹ค. ๋ถ€๋ถ„์ ์ˆ˜๊ฐ€ ์—†๋‹ค๋Š” ๊ฒŒ ์˜คํžˆ๋ ค ๋‹คํ–‰์ด์—ˆ๋‹ค โ€” ์• ๋งคํ•˜๊ฒŒ ๋ฐ˜์ฏค ๋งž์•„ ํ—ค๋งค๋Š” ์ผ์€ ์—†๋‹ค.

๋‘ ์ƒ์ž๊ฐ€ ์ฐธ์กฐํ•˜๋Š” ํ…Œ์ด๋ธ”์€ .data ์— ๊ทธ๋Œ€๋กœ ์žˆ๋‹ค. .data ๋Š” vaddr 0x4000 ์ด ํŒŒ์ผ ์˜คํ”„์…‹ 0x3000 ์ด๋ผ ๊ณ„์‚ฐ์ด ๊ฐ„๋‹จํ•˜๋‹ค.

# dump_tables.py โ€” .data ์—์„œ SR/SQ ํ…Œ์ด๋ธ”๊ณผ memcmp ์ •๋‹ต 32๋ฐ”์ดํŠธ๋ฅผ ๊บผ๋‚ธ๋‹ค
import struct
 
BIN = "prob"
DELTA = 0x1000  # vaddr -> file offset
 
data = open(BIN, "rb").read()
 
 
def dwords(vaddr, n):
    off = vaddr - DELTA
    return list(struct.unpack_from("<%dI" % n, data, off))
 
 
SR = dwords(0x4020, 256)   # S1 ์ด ์ฐธ์กฐํ•˜๋Š” ํ…Œ์ด๋ธ”
SQ = dwords(0x4420, 256)   # S2 ๊ฐ€ ์ฐธ์กฐํ•˜๋Š” ํ…Œ์ด๋ธ”
TARGET = data[0x4820 - DELTA: 0x4820 - DELTA + 32]
 
print("SR[0:16]  =", " ".join("%02x" % v for v in SR[:16]))
print("SQ[0:16]  =", " ".join("%02x" % v for v in SQ[:16]))
print("SR ์ตœ๋Œ€๊ฐ’ =", hex(max(SR)), "/ SQ ์ตœ๋Œ€๊ฐ’ =", hex(max(SQ)))
print("SR ์€ ์ˆœ์—ด์ธ๊ฐ€:", sorted(SR) == list(range(256)))
print("SQ ์€ ์ˆœ์—ด์ธ๊ฐ€:", sorted(SQ) == list(range(256)))
# AES S-box ์ฒซ ์ค„๊ณผ ๋Œ€์กฐ (63 7c 77 7b f2 6b 6f c5 30 01 67 2b fe d7 ab 76)
aes = [0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5,
       0x30, 0x01, 0x67, 0x2B, 0xFE, 0xD7, 0xAB, 0x76]
print("SR == AES S-box ์ฒซ 16๊ฐœ:", SR[:16] == aes)
print()
print("TARGET(32B) =", TARGET.hex())
print("TARGET ascii =", "".join(chr(c) if 32 <= c < 127 else "." for c in TARGET))
python3 dump_tables.py

dump_tables.py ์ถœ๋ ฅ โ€” 0x4020 ์€ AES S-box ์™€ ์™„์ „ํžˆ ์ผ์น˜ํ•˜๊ณ  0x4420 ์€ 25 24 73 67 ๋กœ ์‹œ์ž‘ํ•˜๋Š” ๋‹ค๋ฅธ ์ˆœ์—ด์ด๋‹ค
dump_tables.py ์ถœ๋ ฅ โ€” 0x4020 ์€ AES S-box ์™€ ์™„์ „ํžˆ ์ผ์น˜ํ•˜๊ณ  0x4420 ์€ 25 24 73 67 ๋กœ ์‹œ์ž‘ํ•˜๋Š” ๋‹ค๋ฅธ ์ˆœ์—ด์ด๋‹ค

0x4020 ์€ AES S-box ๋‹ค. 0x4420 ์€ 25 24 73 67 d7 ae 5c 30 ... ์œผ๋กœ ์‹œ์ž‘ํ•˜๋Š” ๋˜ ๋‹ค๋ฅธ 256 ์ˆœ์—ด์ธ๋ฐ, ์ด๊ฒŒ SNOW 3G ๋ช…์„ธ์˜ SQ ๋ฐ•์Šค๋‹ค. ๋‘ ์ƒ์ž๊ฐ€ ๊ฐ๊ฐ c = 0x1b ์™€ c = 0x69 ๋ฅผ ์“ฐ๋Š” ๊ฒƒ๊นŒ์ง€ ๋ช…์„ธ์™€ ๊ฐ™๋‹ค.

๊ทธ๋ฆฌ๊ณ  0x4820 ์˜ 32๋ฐ”์ดํŠธ๊ฐ€ memcmp ์ƒ๋Œ€, ์ฆ‰ ์šฐ๋ฆฌ๊ฐ€ ๋„๋‹ฌํ•ด์•ผ ํ•  ๋ชฉํ‘œ๋‹ค. ASCII ๋กœ๋Š” ์•„๋ฌด ์˜๋ฏธ๊ฐ€ ์—†๋‹ค.


๐Ÿงญ alpha ๊ณฑ์…ˆ โ€” ์ง€๋ฌธ์€ ์—ฌ๊ธฐ ์žˆ์—ˆ๋‹ค

์—ฌ๊ธฐ๊นŒ์ง€๋„ "AES ๋ถ€ํ’ˆ์„ ์“ฐ๋Š” ๋ญ”๊ฐ€"์ผ ๋ฟ์ด๋‹ค. ๊ฒฐ์ •ํƒ€๋Š” 0x1845 ์˜€๋‹ค.

objdump -d -M intel --start-address=0x1855 --stop-address=0x18bc prob | sed -E -f annot_alpha.sed

objdump ๋กœ ๋ณธ MULalpha โ€” ๊ฐ™์€ ์ž…๋ ฅ์— ๋Œ€ํ•ด ์ง€์ˆ˜ 23 245 48 239 ๋กœ MULxPOW ๋ฅผ ๋„ค ๋ฒˆ ๋ถ€๋ฅด๊ณ  c ๋Š” 0xa9 ๋กœ ๊ณ ์ •์ด๋‹ค
objdump ๋กœ ๋ณธ MULalpha โ€” ๊ฐ™์€ ์ž…๋ ฅ์— ๋Œ€ํ•ด ์ง€์ˆ˜ 23 245 48 239 ๋กœ MULxPOW ๋ฅผ ๋„ค ๋ฒˆ ๋ถ€๋ฅด๊ณ  c ๋Š” 0xa9 ๋กœ ๊ณ ์ •์ด๋‹ค

MULxPOW(c, 23, 0xa9), MULxPOW(c, 245, 0xa9), MULxPOW(c, 48, 0xa9), MULxPOW(c, 239, 0xa9).

์ด ๋„ค ์ˆซ์ž ์กฐํ•ฉ์€ ๋‹ค๋ฅธ ๋ฐ์„œ ๋‚˜์˜ฌ ์ˆ˜๊ฐ€ ์—†๋‹ค. SNOW 3G ๋ช…์„ธ์˜ MULalpha ๊ทธ๋Œ€๋กœ๋‹ค. ๋ฐ”๋กœ ์•„๋ž˜ 0x18bc ๋Š” 16, 39, 6, 64 ๋ฅผ ์“ฐ๋Š”๋ฐ ๊ทธ๊ฑด DIValpha ๋‹ค.

์—ฌ๊ธฐ์„œ๋ถ€ํ„ฐ๋Š” ๋ช…์„ธ๋ฅผ ์˜†์— ๋‘๊ณ  ๋Œ€์กฐํ•˜๋Š” ์ž‘์—…์ด ๋๋‹ค. 0x17d3 ์€ FSM ํด๋Ÿญ์ด๋‹ค.

F  = (s15 + R1) ^ R2;      // 32๋น„ํŠธ ๋ง์…ˆ์€ mod 2^32
r  = R2 + (R3 ^ s5);
R3 = S2(R2);
R2 = S1(R1);
R1 = r;
return F;

0x1933 ์€ LFSR ํด๋Ÿญ์ธ๋ฐ, ์ฒซ ์ธ์ž๊ฐ€ 0x69(๋ฌธ์ž 'i') ๋ƒ 0x6b(๋ฌธ์ž 'k') ๋ƒ๋กœ ์ดˆ๊ธฐํ™” ๋ชจ๋“œ์™€ ํ‚ค์ŠคํŠธ๋ฆผ ๋ชจ๋“œ๋ฅผ ๊ฐ€๋ฅธ๋‹ค.

v = (s0 << 8) ^ MULalpha(s0 >> 24) ^ s2 ^ (s11 >> 8) ^ DIValpha(s11 & 0xff);
if (mode == 'i') v ^= F;
for (i = 0; i < 15; i++) s[i] = s[i+1];
s15 = v;

๋ช…์„ธ์™€ ํ•œ ๊ธ€์ž๋„ ๋‹ค๋ฅด์ง€ ์•Š๋‹ค. ๋ฌธ์ œ ์ด๋ฆ„ snow ๋Š” ๋†๋‹ด์ด ์•„๋‹ˆ๋ผ ๊ทธ๋ƒฅ ์ •๋‹ต ํ‘œ๊ธฐ์˜€๋‹ค.


๐Ÿ”‘ ํ‚ค์™€ IV โ€” ์—ฌ๊ธฐ๊ฐ€ ๊ธ‰์†Œ๋‹ค

์ด์ œ ์•ž์—์„œ ๋ณธ Merry-Christmas! ์กฐ๊ฐ์ด ์–ด๋””๋กœ ๋“ค์–ด๊ฐ€๋Š”์ง€ ๋ณผ ์ฐจ๋ก€๋‹ค.

objdump -d -M intel --start-address=0x1aef --stop-address=0x1b6c prob | sed -E -f annot_init.sed

objdump ๋กœ ๋ณธ Initialize โ€” ํ‚ค ๋„ค ์›Œ๋“œ๊ฐ€ ์ฆ‰์น˜๊ฐ’์œผ๋กœ ๋ฐ•ํžˆ๊ณ  IV ๋Š” ์ž…๋ ฅ ๋ฒ„ํผ์˜ 0 4 8 12 ์˜คํ”„์…‹์—์„œ ์ฝํžŒ๋‹ค
objdump ๋กœ ๋ณธ Initialize โ€” ํ‚ค ๋„ค ์›Œ๋“œ๊ฐ€ ์ฆ‰์น˜๊ฐ’์œผ๋กœ ๋ฐ•ํžˆ๊ณ  IV ๋Š” ์ž…๋ ฅ ๋ฒ„ํผ์˜ 0 4 8 12 ์˜คํ”„์…‹์—์„œ ์ฝํžŒ๋‹ค

ํ‚ค๋Š” k[0]=0x2173616d, k[1]=0x74736972, k[2]=0x68432d79, k[3]=0x7272654d ๋กœ ๊ณ ์ •์ด๋‹ค. ๋ฆฌํ‹€์—”๋””์–ธ ๋ฐ”์ดํŠธ๋กœ ํŽด๋ฉด mas! rist y-Ch Merr ์ด๊ณ , ์›Œ๋“œ๋ฅผ ๋’ค์—์„œ๋ถ€ํ„ฐ ์ฝ์œผ๋ฉด Merry-Christmas! ๊ฐ€ ๋œ๋‹ค.

IV ๋Š” ๋‹ค๋ฅด๋‹ค. rbp-0x38 ์— ๋“ค์–ด์˜จ ํฌ์ธํ„ฐ โ€” ์ฆ‰ ์‚ฌ์šฉ์ž ์ž…๋ ฅ ๋ฒ„ํผ โ€” ์—์„œ 0, 4, 8, 12 ์˜คํ”„์…‹์˜ 32๋น„ํŠธ๋ฅผ ๊ทธ๋Œ€๋กœ ์ฝ๋Š”๋‹ค.

์ •๋ฆฌํ•˜๋ฉด LFSR ์ดˆ๊ธฐ ์ƒํƒœ๋Š” ์ด๋ ‡๊ฒŒ ์ฑ„์›Œ์ง„๋‹ค. F ๋Š” 0xffffffff ๋‹ค.

์Šฌ๋กฏ๊ฐ’์Šฌ๋กฏ๊ฐ’
s15k[3] ^ IV[0]s7k[3]
s14k[2]s6k[2]
s13k[1]s5k[1]
s12k[0] ^ IV[1]s4k[0]
s11k[3] ^ Fs3k[3] ^ F
s10k[2] ^ F ^ IV[2]s2k[2] ^ F
s9k[1] ^ F ^ IV[3]s1k[1] ^ F
s8k[0] ^ Fs0k[0] ^ F

๊ทธ๋‹ค์Œ 32๋ผ์šด๋“œ๋ฅผ ์ดˆ๊ธฐํ™” ๋ชจ๋“œ๋กœ ๋Œ๋ฆฌ๊ณ , ๋งˆ์ง€๋ง‰์— ClockFSM() ์„ ํ•œ ๋ฒˆ ๋” ๋ถ€๋ฅด๊ณ  ๋ฐ˜ํ™˜๊ฐ’์„ ๋ฒ„๋ฆฐ๋‹ค. 0x1c22 ์˜ ๊ทธ ํ•œ ์ค„์ด ์žˆ๊ณ  ์—†๊ณ ๋กœ ์ดํ›„ ๋ชจ๋“  ํ‚ค์ŠคํŠธ๋ฆผ์ด ๋‹ฌ๋ผ์ง„๋‹ค.

โ–ถ๐Ÿ› ์‚ฝ์งˆ 2 โ€” ๋ช…์„ธ ๊ฐ๊ฐ๋Œ€๋กœ ๋‘๋ฉด ์•ˆ ๋˜๋Š” ๋‘ ์ž๋ฆฌ

ํ‘œ์ค€ ๋ฌธ์„œ๋ฅผ ์˜†์— ๋‘๊ณ  ์˜ฎ๊ธฐ๋‹ค ๋ณด๋ฉด ์†์ด ๋จผ์ € ๋‚˜๊ฐ€๋Š” ์ž๋ฆฌ๊ฐ€ ์žˆ๋‹ค. ๋‘ ๊ฐœ๋ฅผ ์‹ค์ œ๋กœ ํ‹€๋ฆฌ๊ฒŒ ๋งŒ๋“ค์–ด ๋Œ๋ ค ๋ดค๋‹ค.

ํ•˜๋‚˜๋Š” ์œ„์—์„œ ๋งํ•œ ์ดˆ๊ธฐํ™” ๊ผฌ๋ฆฌ์˜ ClockFSM() ์ด๋‹ค. 32๋ผ์šด๋“œ๋กœ ๋๋‚ฌ๋‹ค๊ณ  ์ƒ๊ฐํ•˜๊ธฐ ์‰ฝ๋‹ค.

๋‹ค๋ฅธ ํ•˜๋‚˜๋Š” IV ์›Œ๋“œ์˜ ๋ฐ”์ดํŠธ ์ˆœ์„œ๋‹ค. ๋ช…์„ธ์—์„œ IV ๋Š” IV[0] ์ด ์ตœ์ƒ์œ„์ธ ๊ฒƒ์ฒ˜๋Ÿผ ํ‘œ๊ธฐ๋˜๋Š”๋ฐ, ์ด ๋ฐ”์ด๋„ˆ๋ฆฌ๋Š” mov eax, DWORD PTR [rax] ๋กœ ๊ทธ๋ƒฅ ์ฝ๋Š”๋‹ค. x86 ์ด๋‹ˆ ๋ฆฌํ‹€์—”๋””์–ธ์ด๋‹ค. ๋น…์—”๋””์–ธ์œผ๋กœ ์กฐ๋ฆฝํ•˜๋ฉด ์กฐ์šฉํžˆ ๋‹ค๋ฅธ ๊ฐ’์ด ๋œ๋‹ค.

# sapjil_variants.py โ€” ์ดˆ๊ธฐํ™” ๊ผฌ๋ฆฌ๋ฅผ ๋นผ๊ฑฐ๋‚˜ IV ๋ฅผ ๋น…์—”๋””์–ธ์œผ๋กœ ์ฝ์œผ๋ฉด
def main():
    _, _, TARGET = load_tables("prob")
    for name, cls, be in (("binary ", Snow3G, False),
                          ("no_tail", NoTailFSM, False),
                          ("be_iv  ", Snow3G, True)):
        surv, printable = run(cls, TARGET, be)
        head = printable[0].decode() if printable else "-"
        print("%s ์ž๊ธฐ๋ฌด๋ชจ์ˆœ %d๊ฐœ / printable %d๊ฐœ   ์•ž 16๋ฐ”์ดํŠธ: %s" %
              (name, len(surv), len(printable), head))
python3 sapjil_variants.py

์„ธ ๋ณ€์ข… ๋น„๊ต ์ถœ๋ ฅ โ€” ๋ฐ”์ด๋„ˆ๋ฆฌ ๊ทธ๋Œ€๋กœ๋ฉด printable 1๊ฐœ๊ฐ€ ๋‚˜์˜ค์ง€๋งŒ ๊ผฌ๋ฆฌ๋ฅผ ๋นผ๊ฑฐ๋‚˜ ๋น…์—”๋””์–ธ์ด๋ฉด 0๊ฐœ๋‹ค
์„ธ ๋ณ€์ข… ๋น„๊ต ์ถœ๋ ฅ โ€” ๋ฐ”์ด๋„ˆ๋ฆฌ ๊ทธ๋Œ€๋กœ๋ฉด printable 1๊ฐœ๊ฐ€ ๋‚˜์˜ค์ง€๋งŒ ๊ผฌ๋ฆฌ๋ฅผ ๋นผ๊ฑฐ๋‚˜ ๋น…์—”๋””์–ธ์ด๋ฉด 0๊ฐœ๋‹ค

๋‘˜ ๋‹ค printable ํ›„๋ณด 0๊ฐœ๋‹ค.

์žฌ๋ฏธ์žˆ๋Š” ๊ฑด ์ž๊ธฐ๋ฌด๋ชจ์ˆœ ํ›„๋ณด๊ฐ€ 3๊ฐœ, 2๊ฐœ์”ฉ์€ ์—ฌ์ „ํžˆ ๋‚˜์˜จ๋‹ค๋Š” ์ ์ด๋‹ค. "๋ช‡ ๊ฐœ ์‚ด์•„๋‚จ์•˜๋‹ค"๋Š” ๊ฒƒ ์ž์ฒด๋Š” ์•„๋ฌด ๋ณด์ฆ์ด ์•ˆ ๋œ๋‹ค. ์‚ด์•„๋‚จ์€ ๊ฐ’์ด ์ฝ์„ ์ˆ˜ ์žˆ๋Š” ๊ธ€์ž์ธ๊ฐ€๊นŒ์ง€ ๋ด์•ผ ๋น„๋กœ์†Œ ์‹ ํ˜ธ๊ฐ€ ๋œ๋‹ค.

๋ง๋ถ™์ด๋ฉด, ํ˜ธ์ถœ ์ˆœ์„œ๋Š” ํ‹€๋ ค๋„ ํ‹ฐ๊ฐ€ ์•ˆ ๋‚œ๋‹ค. ๋ช…์„ธ๋Š” ์›Œ๋“œ๋ฅผ ๋จผ์ € ๋ฝ‘๊ณ  LFSR ์„ ๋ฏธ๋Š”๋ฐ ์ด ๋ฐ”์ด๋„ˆ๋ฆฌ๋Š” ๋ฐ˜๋Œ€๋‹ค. ๊ทธ๋Ÿฐ๋ฐ ๋ช…์„ธ๊ฐ€ ์ดˆ๊ธฐํ™” ์งํ›„ ํด๋Ÿญ์„ ํ•œ ๋ฒˆ ๋” ๋„ฃ์œผ๋ผ๊ณ  ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๊ฒฐ๊ตญ ๊ฐ™์€ ์ˆ˜์—ด์ด ๋‚˜์˜จ๋‹ค. ์ด๊ฑด ํ™•์ธํ•ด ๋ณด๊ณ  ๋‚˜์„œ์•ผ ์•Œ์•˜๋‹ค.



๐ŸŽฏ main ์ด ํ•˜๋Š” ์ผ

์ด์ œ ๋งˆ์ง€๋ง‰ ์กฐ๊ฐ์ด๋‹ค.

objdump -d -M intel --start-address=0x1d22 --stop-address=0x1db8 prob | sed -E -f annot_main.sed

objdump ๋กœ ๋ณธ main ์˜ ๋ณ€ํ™˜ ๋ฃจํ”„ โ€” ์›Œ๋“œ๋งˆ๋‹ค 0x3f2c ๋ฅผ XOR ํ•˜๊ณ  ํ‚ค์ŠคํŠธ๋ฆผ ์ตœํ•˜์œ„ ๋น„ํŠธ๊ฐ€ 1์ด๋ฉด 16๋น„ํŠธ NOT ์„ ๊ฑด๋‹ค
objdump ๋กœ ๋ณธ main ์˜ ๋ณ€ํ™˜ ๋ฃจํ”„ โ€” ์›Œ๋“œ๋งˆ๋‹ค 0x3f2c ๋ฅผ XOR ํ•˜๊ณ  ํ‚ค์ŠคํŠธ๋ฆผ ์ตœํ•˜์œ„ ๋น„ํŠธ๊ฐ€ 1์ด๋ฉด 16๋น„ํŠธ NOT ์„ ๊ฑด๋‹ค

C ๋กœ ์˜ฎ๊ธฐ๋ฉด ์ด๊ฒŒ ์ „๋ถ€๋‹ค.

if (argc != 2)              { printf("usage: %s <string>", argv[0]); exit(-1); }
if (strlen(argv[1]) != 32)  { puts("length of string must be 32."); exit(-1); }
 
char buf[32] = {0};
strcpy(buf, argv[1]);
Initialize(buf);                      // IV = buf[0..15]
 
for (int i = 0; i < 16; i++) {
    uint16_t *w = (uint16_t *)(buf + 2*i);
    *w ^= 0x3f2c;
    if (GenerateKeystream() & 1)      // 32๋น„ํŠธ ์›Œ๋“œ์—์„œ ์ตœํ•˜์œ„ 1๋น„ํŠธ๋งŒ
        *w = ~*w;
}
puts(memcmp(target, buf, 32) == 0 ? "Correct!" : "Wrong...");

32๋น„ํŠธ ํ‚ค์ŠคํŠธ๋ฆผ ์›Œ๋“œ๋ฅผ ํ†ต์งธ๋กœ ๋ฝ‘์•„ ๋†“๊ณ  1๋น„ํŠธ๋งŒ ์“ด๋‹ค. ๋‚˜๋จธ์ง€ 31๋น„ํŠธ๋Š” ๋ฒ„๋ฆฐ๋‹ค.

์•”ํ˜ธํ•™์ ์œผ๋กœ๋Š” ์•„๊น์ง€๋งŒ, ํ‘ธ๋Š” ์ชฝ์—์„œ๋Š” ์ด๊ฒŒ ์ „๋ถ€๋‹ค. ์›Œ๋“œ ํ•˜๋‚˜๋ฅผ ๋˜๋Œ๋ฆฌ๋Š” ๋ฐ ํ•„์š”ํ•œ ์ •๋ณด๊ฐ€ ํ•œ ๋น„ํŠธ๋ฟ์ด๋ผ๋Š” ๋œป์ด๋‹ˆ๊นŒ.


๐Ÿ’ก ํ•ต์‹ฌ โ€” ์ž๊ธฐ์ฐธ์กฐ๋ฅผ 8๋น„ํŠธ๋กœ ์ ‘๋Š”๋‹ค

์ฒ˜์Œ ์ด ๊ตฌ์กฐ๋ฅผ ๋ณด๊ณ  ๋“  ์ƒ๊ฐ์€ "๋‹ญ์ด ๋จผ์ €๋ƒ"์˜€๋‹ค. ํ‚ค์ŠคํŠธ๋ฆผ์„ ์•Œ์•„์•ผ ์ž…๋ ฅ์„ ๋˜๋Œ๋ฆฌ๋Š”๋ฐ, ํ‚ค์ŠคํŠธ๋ฆผ์€ ๊ทธ ์ž…๋ ฅ์˜ ์•ž 16๋ฐ”์ดํŠธ๋กœ ๋งŒ๋“ค์–ด์ง„๋‹ค.

๊ทธ๋Ÿฐ๋ฐ ์กฐ๊ธˆ๋งŒ ๋“ค์—ฌ๋‹ค๋ณด๋ฉด ๊ณ ๋ฆฌ๊ฐ€ ์ƒ๊ฐ๋ณด๋‹ค ์–‡๋‹ค.

๋ชฉํ‘œ ์›Œ๋“œ๋ฅผ t_i, ํ‚ค์ŠคํŠธ๋ฆผ ์›Œ๋“œ๋ฅผ z_i ๋ผ ํ•˜์ž. ๋ณ€ํ™˜์€ XOR ํ•œ ๋ฒˆ๊ณผ ์กฐ๊ฑด๋ถ€ NOT ํ•œ ๋ฒˆ๋ฟ์ด๊ณ  ๋‘˜ ๋‹ค ์ž๊ธฐ์—ญ์›์ด๋‹ค. ๊ทธ๋ž˜์„œ ์—ญ์‚ฐ์€ ์ด๋ ‡๊ฒŒ ๋๋‚œ๋‹ค.

z_i ์˜ ์ตœํ•˜์œ„ ๋น„ํŠธ๊ฐ€ 0 ์ด๋ฉด   ์›๋ž˜ ์›Œ๋“œ = t_i ^ 0x3f2c
z_i ์˜ ์ตœํ•˜์œ„ ๋น„ํŠธ๊ฐ€ 1 ์ด๋ฉด   ์›๋ž˜ ์›Œ๋“œ = (~t_i) ^ 0x3f2c

์›Œ๋“œ ํ•˜๋‚˜๋‹น ๋ฏธ์ง€์ˆ˜๋Š” ๋”ฑ 1๋น„ํŠธ๋‹ค.

๊ทธ๋ฆฌ๊ณ  IV ๋ฅผ ์ด๋ฃจ๋Š” ๊ฒƒ์€ ์•ž 16๋ฐ”์ดํŠธ, ์ฆ‰ ์›Œ๋“œ 07 ์ด๋‹ค. ์ด ์—ฌ๋Ÿ ๊ฐœ๋งŒ ์ •ํ•ด์ง€๋ฉด ํ‚ค์ŠคํŠธ๋ฆผ ์ „์ฒด๊ฐ€ ๊ฒฐ์ •๋œ๋‹ค. ๋’ค์ชฝ ์›Œ๋“œ 815 ๋Š” IV ์— ์•„๋ฌด ์˜ํ–ฅ์„ ์ฃผ์ง€ ์•Š๋Š”๋‹ค.

๊ทธ๋Ÿฌ๋‹ˆ ์ ˆ์ฐจ๋Š” ์ด๋ ‡๊ฒŒ ๋œ๋‹ค.

  1. b0..b7 ์—ฌ๋Ÿ ๋น„ํŠธ๋ฅผ ๊ฐ€์ •ํ•œ๋‹ค โ€” ๊ฒฝ์šฐ์˜ ์ˆ˜ 256.
  2. ๊ทธ ๊ฐ€์ •์œผ๋กœ ์•ž 16๋ฐ”์ดํŠธ๋ฅผ ์—ญ์‚ฐํ•ด IV ๋ฅผ ๋งŒ๋“ ๋‹ค.
  3. ๊ทธ IV ๋กœ SNOW 3G ๋ฅผ ์‹ค์ œ๋กœ ๋Œ๋ ค z_0..z_7 ์„ ๋ฝ‘๋Š”๋‹ค.
  4. ๋ฝ‘ํžŒ ์ตœํ•˜์œ„ ๋น„ํŠธ๋“ค์ด ๊ฐ€์ •๊ณผ ๊ฐ™์€์ง€ ๋ณธ๋‹ค. ๋‹ค๋ฅด๋ฉด ๊ทธ ๊ฐ€์ •์€ ์ž๊ธฐ๋ชจ์ˆœ์ด๋‹ˆ ๋ฒ„๋ฆฐ๋‹ค.
  5. ์‚ด์•„๋‚จ์€ ๊ฐ€์ •์—์„œ z_8..z_15 ๋กœ ๋’ค 16๋ฐ”์ดํŠธ๋ฅผ ๋งˆ์ € ์—ญ์‚ฐํ•œ๋‹ค.

2^128 ์ฒ˜๋Ÿผ ๋ณด์ด๋˜ ๋ฌธ์ œ๊ฐ€ 2^8 ์ด ๋œ๋‹ค. ๋…ธํŠธ๋ถ์—์„œ 1์ดˆ๋„ ์•ˆ ๊ฑธ๋ฆฐ๋‹ค.



๐Ÿš€ Full Exploit

SNOW 3G ๋ถ€๋ถ„์€ ํŒŒ์ผ์„ ๋‚˜๋ˆ  ๋’€๋‹ค. ๋ช…์„ธ๋ฅผ ์˜ฎ๊ธด ๊ฒŒ ์•„๋‹ˆ๋ผ ๋””์Šค์–ด์…ˆ๋ธ”๋ฆฌ๋ฅผ ์˜ฎ๊ธด ๊ฒƒ์ด๋ผ, ์œ„์—์„œ ํ™•์ธํ•œ ์ฃผ์†Œ๋ฅผ ์ฃผ์„์— ๋‚จ๊ฒผ๋‹ค.

# snow3g.py
"""prob ์•ˆ์— ๋ฐ•ํ˜€ ์žˆ๋Š” SNOW 3G ๋ฅผ ํŒŒ์ด์ฌ์œผ๋กœ ๊ทธ๋Œ€๋กœ ์˜ฎ๊ธด ๊ฒƒ.
 
๋ฐ”์ด๋„ˆ๋ฆฌ์—์„œ ํ™•์ธํ•œ ๋Œ€์‘ ๊ด€๊ณ„:
  0x1209 MULx(V, c)            0x1240 MULxPOW(V, i, c)
  0x128b S1(w)  <- SR @0x4020, c=0x1b
  0x1530 S2(w)  <- SQ @0x4420, c=0x69
  0x1845 MULalpha(c)           0x18bc DIValpha(c)
  0x17d3 ClockFSM()            0x1933 ClockLFSR(mode, F)   mode 0x69='i' / 0x6b='k'
  0x1adf Initialize(buf)       0x1c2f GenerateKeystream()
LFSR s0..s15 ๋Š” .bss 0x4860, R1/R2/R3 ๋Š” 0x48a0/0x48a4/0x48a8 (์ „๋ถ€ 0์œผ๋กœ ์‹œ์ž‘).
"""
import struct
 
DELTA = 0x1000  # .data: vaddr 0x4000 == file offset 0x3000
 
M32 = 0xFFFFFFFF
# ๋ฐ”์ด๋„ˆ๋ฆฌ ์•ˆ ๊ณ ์ • ํ‚ค. ์›Œ๋“œ ๋‹จ์œ„๋กœ ๋’ค์ง‘ํ˜€ ์žˆ์–ด k[3]..k[0] ์„ ์ด์–ด ๋ถ™์ด๋ฉด "Merry-Christmas!".
KEY = [0x2173616D, 0x74736972, 0x68432D79, 0x7272654D]
 
 
def load_tables(path="prob"):
    data = open(path, "rb").read()
    sr = list(struct.unpack_from("<256I", data, 0x4020 - DELTA))
    sq = list(struct.unpack_from("<256I", data, 0x4420 - DELTA))
    target = data[0x4820 - DELTA: 0x4820 - DELTA + 32]
    return sr, sq, target
 
 
class Snow3G:
    def __init__(self, sr, sq):
        self.SR, self.SQ = sr, sq
 
    # --- GF(2^8) ํ—ฌํผ -------------------------------------------------
    @staticmethod
    def MULx(V, c):
        return ((V << 1) & 0xFF) ^ c if V & 0x80 else (V << 1) & 0xFF
 
    def MULxPOW(self, V, i, c):
        for _ in range(i):
            V = self.MULx(V, c)
        return V & 0xFF
 
    def _box(self, w, T, c):
        """S1/S2 ๊ณตํ†ต ๊ณจ๊ฒฉ โ€” ํ…Œ์ด๋ธ”๊ณผ ๊ธฐ์•ฝ๋‹คํ•ญ์‹ ์ƒ์ˆ˜๋งŒ ๋‹ค๋ฅด๋‹ค."""
        w0, w1, w2, w3 = (w >> 24) & 0xFF, (w >> 16) & 0xFF, (w >> 8) & 0xFF, w & 0xFF
        t0, t1, t2, t3 = T[w0], T[w1], T[w2], T[w3]
        m = lambda v: self.MULx(v, c)
        r0 = m(t0) ^ t1 ^ t2 ^ m(t3) ^ t3
        r1 = m(t0) ^ t0 ^ m(t1) ^ t2 ^ t3
        r2 = t0 ^ m(t1) ^ t1 ^ m(t2) ^ t3
        r3 = t0 ^ t1 ^ m(t2) ^ t2 ^ m(t3)
        return ((r0 << 24) | (r1 << 16) | (r2 << 8) | r3) & M32
 
    def S1(self, w):
        return self._box(w, self.SR, 0x1B)
 
    def S2(self, w):
        return self._box(w, self.SQ, 0x69)
 
    def MULalpha(self, c):
        return ((self.MULxPOW(c, 23, 0xA9) << 24) | (self.MULxPOW(c, 245, 0xA9) << 16) |
                (self.MULxPOW(c, 48, 0xA9) << 8) | self.MULxPOW(c, 239, 0xA9))
 
    def DIValpha(self, c):
        return ((self.MULxPOW(c, 16, 0xA9) << 24) | (self.MULxPOW(c, 39, 0xA9) << 16) |
                (self.MULxPOW(c, 6, 0xA9) << 8) | self.MULxPOW(c, 64, 0xA9))
 
    # --- ์ƒํƒœ ๊ฐฑ์‹  ----------------------------------------------------
    def ClockFSM(self):
        s = self.s
        F = ((s[15] + self.R1) & M32) ^ self.R2
        r = (self.R2 + (self.R3 ^ s[5])) & M32
        self.R3 = self.S2(self.R2)
        self.R2 = self.S1(self.R1)
        self.R1 = r
        return F
 
    def ClockLFSR(self, mode, F=0):
        s = self.s
        v = (((s[0] << 8) & M32) ^ self.MULalpha(s[0] >> 24) ^ s[2] ^
             (s[11] >> 8) ^ self.DIValpha(s[11] & 0xFF))
        if mode == "i":
            v ^= F
        self.s = s[1:] + [v & M32]
 
    # --- ํ‚ค ์Šค์ผ€์ค„ / ํ‚ค์ŠคํŠธ๋ฆผ ----------------------------------------
    def initialize(self, iv):
        k, F = KEY, 0xFFFFFFFF
        self.s = [
            k[0] ^ F, k[1] ^ F, k[2] ^ F, k[3] ^ F,          # s0..s3
            k[0], k[1], k[2], k[3],                          # s4..s7
            k[0] ^ F, k[1] ^ F ^ iv[3], k[2] ^ F ^ iv[2], k[3] ^ F,   # s8..s11
            k[0] ^ iv[1], k[1], k[2], k[3] ^ iv[0],          # s12..s15
        ]
        self.R1 = self.R2 = self.R3 = 0
        for _ in range(32):
            self.ClockLFSR("i", self.ClockFSM())
        self.ClockFSM()   # ์ดˆ๊ธฐํ™” ๋งˆ์ง€๋ง‰ ํ•œ ๋ฒˆ โ€” ๋ฐ˜ํ™˜๊ฐ’์€ ๋ฒ„๋ฆฐ๋‹ค
 
    def keystream_word(self):
        self.ClockLFSR("k")
        return (self.ClockFSM() ^ self.s[0]) & M32

ํ’€์ด ๋ณธ์ฒด๋Š” ์œ„์—์„œ ์ •๋ฆฌํ•œ ๋‹ค์„ฏ ๋‹จ๊ณ„๋ฅผ ๊ทธ๋Œ€๋กœ ์˜ฎ๊ธด ๊ฒƒ์ด๋‹ค.

# solve.py
"""snow (Dreamhack, Silver 1 / reversing) ํ’€์ด.
 
main ์ด ํ•˜๋Š” ์ผ:
    strlen(argv[1]) == 32 ๊ฐ•์ œ โ†’ 32๋ฐ”์ดํŠธ๋ฅผ ์Šคํƒ ๋ฒ„ํผ๋กœ strcpy
    Initialize(buf)            โ† IV = buf[0:16] (u32 4๊ฐœ, ๋ฆฌํ‹€์—”๋””์–ธ)
    for i in 0..15:
        w  = *(u16*)(buf+2i);  w ^= 0x3f2c;  *(u16*)(buf+2i) = w
        z  = GenerateKeystream()
        if z & 1:  *(u16*)(buf+2i) = ~w
    memcmp(TARGET, buf, 32) == 0  โ†’ "Correct!"
 
ํ•ต์‹ฌ: ํ‚ค์ŠคํŠธ๋ฆผ์€ IV, ์ฆ‰ **์ž…๋ ฅ์˜ ์•ž 16๋ฐ”์ดํŠธ์—๋งŒ** ์˜์กดํ•œ๋‹ค. ๊ทธ๋Ÿฐ๋ฐ ๊ทธ ์•ž 16๋ฐ”์ดํŠธ๋Š”
์›Œ๋“œ 0~7 ์ด๊ณ , ๊ฐ ์›Œ๋“œ์˜ ์—ญ์‚ฐ์€ z_i ์˜ LSB ํ•œ ๋น„ํŠธ๋งŒ ์•Œ๋ฉด ๋๋‚œ๋‹ค.
๋”ฐ๋ผ์„œ b0..b7 8๋น„ํŠธ(=256๊ฐ€์ง€)๋งŒ ๊ฐ€์ •ํ•˜๋ฉด ์•ž 16๋ฐ”์ดํŠธ๊ฐ€ ์ •ํ•ด์ง€๊ณ , ๊ทธ๊ฑธ๋กœ ์‹ค์ œ
ํ‚ค์ŠคํŠธ๋ฆผ์„ ๋Œ๋ ค ๊ฐ€์ •์ด ์ž๊ธฐ๋ชจ์ˆœ์ด ์•„๋‹Œ์ง€ ํ™•์ธํ•˜๋ฉด ๋œ๋‹ค. ์‚ด์•„๋‚จ์€ ํ›„๋ณด์—์„œ
z_8..z_15 ๋กœ ๋’ท 16๋ฐ”์ดํŠธ๋ฅผ ๋งˆ์ € ์—ญ์‚ฐํ•œ๋‹ค.
"""
import struct
import sys
 
from snow3g import Snow3G, load_tables
 
XOR = 0x3F2C
 
 
def words_of(buf):
    return list(struct.unpack("<16H", buf))
 
 
def invert(target_w, bit):
    """์ •๋‹ต ์›Œ๋“œ์™€ z ์˜ LSB ๋กœ ์›๋ž˜ ์ž…๋ ฅ ์›Œ๋“œ๋ฅผ ๋˜๋Œ๋ฆฐ๋‹ค."""
    w = (~target_w) & 0xFFFF if bit else target_w
    return w ^ XOR
 
 
def main():
    SR, SQ, TARGET = load_tables(sys.argv[1] if len(sys.argv) > 1 else "prob")
    tw = words_of(TARGET)
    print("TARGET   :", TARGET.hex())
 
    hits = []
    for guess in range(256):
        bits = [(guess >> i) & 1 for i in range(8)]
        head = b"".join(struct.pack("<H", invert(tw[i], bits[i])) for i in range(8))
        iv = list(struct.unpack("<4I", head))
 
        c = Snow3G(SR, SQ)
        c.initialize(iv)
        z = [c.keystream_word() for _ in range(16)]
 
        if [zi & 1 for zi in z[:8]] != bits:      # ๊ฐ€์ •์ด ์ž๊ธฐ๋ชจ์ˆœ์ด๋ฉด ๋ฒ„๋ฆฐ๋‹ค
            continue
        tail = b"".join(struct.pack("<H", invert(tw[8 + i], z[8 + i] & 1)) for i in range(8))
        hits.append((guess, head + tail, z))
 
    print("๊ฐ€์ • 256๊ฐœ ์ค‘ ์ž๊ธฐ๋ชจ์ˆœ ์—†์ด ์‚ด์•„๋‚จ์€ ๊ฒƒ:", len(hits))
    answer = None
    for guess, cand, z in hits:
        printable = all(32 <= b < 127 for b in cand)
        print("  b0..b7=0x%02x  printable=%-5s  %s" % (
            guess, printable, cand.decode() if printable else cand.hex()))
        if not printable:
            continue
 
        # ์ •๋ฐฉํ–ฅ์œผ๋กœ ๋‹ค์‹œ ๋Œ๋ ค memcmp ๊ฐ€ ์‹ค์ œ๋กœ ํ†ต๊ณผํ•˜๋Š”์ง€ ํ™•์ธ
        buf = bytearray(cand)
        c = Snow3G(SR, SQ)
        c.initialize(list(struct.unpack("<4I", cand[:16])))
        for i in range(16):
            w = struct.unpack_from("<H", buf, 2 * i)[0] ^ XOR
            if c.keystream_word() & 1:
                w = (~w) & 0xFFFF
            struct.pack_into("<H", buf, 2 * i, w)
        ok = bytes(buf) == TARGET
        print("  ์ •๋ฐฉํ–ฅ ์žฌํ˜„ =", bytes(buf).hex(), "โ†’ ์ผ์น˜" if ok else "โ†’ ๋ถˆ์ผ์น˜")
        if ok:
            answer = cand.decode()
 
    if answer:
        print()
        print("ANSWER:", answer)
 
 
if __name__ == "__main__":
    main()
python3 solve.py

solve.py ์‹คํ–‰ ๊ฒฐ๊ณผ โ€” 256๊ฐ€์ง€ ์ค‘ 4๊ฐœ๊ฐ€ ์ž๊ธฐ๋ฌด๋ชจ์ˆœ์œผ๋กœ ๋‚จ๊ณ  ๊ทธ ์ค‘ ์ฝ์„ ์ˆ˜ ์žˆ๋Š” ํ•˜๋‚˜๊ฐ€ ํ”Œ๋ž˜๊ทธ๋‹ค
solve.py ์‹คํ–‰ ๊ฒฐ๊ณผ โ€” 256๊ฐ€์ง€ ์ค‘ 4๊ฐœ๊ฐ€ ์ž๊ธฐ๋ฌด๋ชจ์ˆœ์œผ๋กœ ๋‚จ๊ณ  ๊ทธ ์ค‘ ์ฝ์„ ์ˆ˜ ์žˆ๋Š” ํ•˜๋‚˜๊ฐ€ ํ”Œ๋ž˜๊ทธ๋‹ค

์‚ด์•„๋‚จ์€ ํ›„๋ณด๊ฐ€ 4๊ฐœ๋‹ค. ๋‚˜๋จธ์ง€ ์…‹์€ ๋ฐ”์ดํŠธ๊ฐ€ ๊นจ์ ธ ์žˆ์–ด 32๊ธ€์ž ๋ฌธ์ž์—ด๋กœ ์„ฑ๋ฆฝํ•˜์ง€ ์•Š๋Š”๋‹ค.

์ฝํžˆ๋Š” ํ•˜๋‚˜๋Š” DH{F805042AC5E59FD07ABEF1E9B2EF}. ์ •๋ฐฉํ–ฅ์œผ๋กœ ๋‹ค์‹œ ๋Œ๋ ค ๋ด๋„ .data ์˜ 32๋ฐ”์ดํŠธ์™€ ์ •ํ™•ํžˆ ๊ฐ™๋‹ค.



๐Ÿงช ๊ฒ€์ฆ โ€” ๋ชจ๋ธ์ด ์ •๋ง ๊ทธ ๋ฐ”์ด๋„ˆ๋ฆฌ์ธ๊ฐ€

ํŒŒ์ด์ฌ์œผ๋กœ ์˜ฎ๊ธด ๊ฒŒ ์ง„์งœ ์ด ๋ฐ”์ด๋„ˆ๋ฆฌ์™€ ๊ฐ™์€์ง€๋Š” ๋”ฐ๋กœ ํ™•์ธํ•ด์•ผ ํ•œ๋‹ค. ์ •๋‹ต ํ•˜๋‚˜๊ฐ€ ๋งž์•˜๋‹ค๋Š” ๊ฒƒ๋งŒ์œผ๋กœ๋Š” ์šฐ์—ฐ์ผ ์—ฌ์ง€๊ฐ€ ๋‚จ๋Š”๋‹ค.

PIE ๋ผ ์ฃผ์†Œ๋ฅผ ๊ด€๋ก€๋กœ ๊ฐ€์ •ํ•˜๋ฉด ์•ˆ ๋œ๋‹ค. gdb ๋ฐฐ์น˜ ์Šคํฌ๋ฆฝํŠธ ์•ˆ์—์„œ info proc mappings ๋กœ ๋กœ๋“œ ๋ฒ ์ด์Šค๋ฅผ ์ง์ ‘ ์ฝ์—ˆ๋‹ค.

# verify.gdb
set confirm off
set pagination off
set args DH{F805042AC5E59FD07ABEF1E9B2EF}
starti
python
import gdb
base = None
for ln in gdb.execute("info proc mappings", to_string=True).splitlines():
    f = ln.split()
    if len(f) >= 5 and f[-1].endswith("/prob"):
        base = int(f[0], 16)
        break
gdb.execute("set $b = 0x%x" % base)
print("PIE base = 0x%x  (๊ด€๋ก€ ๊ฐ€์ • ๊ธˆ์ง€ โ€” info proc mappings ๋กœ ์ฝ์—ˆ๋‹ค)" % base)
end
break *($b + 0x1d22)
break *($b + 0x1d99)
continue
printf "\n[Initialize ์งํ›„] LFSR s0..s15\n"
x/16xw $b+0x4860
printf "[Initialize ์งํ›„] R1 R2 R3\n"
x/3xw $b+0x48a0
continue
printf "\n[memcmp ์ง์ „] ๋ณ€ํ™˜๋œ ์ž…๋ ฅ ๋ฒ„ํผ 32๋ฐ”์ดํŠธ\n"
x/32xb $rbp-0x30
printf "[memcmp ์ง์ „] .data 0x4820 ์˜ ์ •๋‹ต 32๋ฐ”์ดํŠธ\n"
x/32xb $b+0x4820
continue
gdb -q -batch -x verify.gdb ./prob

gdb ๋Ÿฐํƒ€์ž„ ํ™•์ธ โ€” Initialize ์งํ›„ LFSR 16์›Œ๋“œ์™€ R1 R2 R3 ๋ฅผ ๋คํ”„ํ•˜๊ณ  memcmp ์ง์ „ ๋ฒ„ํผ๊ฐ€ ์ •๋‹ต๊ณผ ๊ฐ™์Œ์„ ๋ณด์ธ๋‹ค
gdb ๋Ÿฐํƒ€์ž„ ํ™•์ธ โ€” Initialize ์งํ›„ LFSR 16์›Œ๋“œ์™€ R1 R2 R3 ๋ฅผ ๋คํ”„ํ•˜๊ณ  memcmp ์ง์ „ ๋ฒ„ํผ๊ฐ€ ์ •๋‹ต๊ณผ ๊ฐ™์Œ์„ ๋ณด์ธ๋‹ค

๋‘ ์ง€์ ์„ ๋ดค๋‹ค. Initialize ๊ฐ€ ๋๋‚œ ์งํ›„์˜ LFSR 16์›Œ๋“œ์™€ FSM ์„ธ ๋ ˆ์ง€์Šคํ„ฐ, ๊ทธ๋ฆฌ๊ณ  memcmp ์ง์ „ ์Šคํƒ ๋ฒ„ํผ์™€ .data ์˜ ๋ชฉํ‘œ๊ฐ’.

๋ฒ„ํผ 32๋ฐ”์ดํŠธ๊ฐ€ ๋ชฉํ‘œ์™€ ๋ฐ”์ดํŠธ ๋‹จ์œ„๋กœ ๊ฐ™๊ณ , ๋งˆ์ง€๋ง‰์— Correct! ๊ฐ€ ์ฐํžŒ๋‹ค.

์ด์ œ ํŒŒ์ด์ฌ ๋ชจ๋ธ์ด ๊ฐ™์€ ์ค‘๊ฐ„ ์ƒํƒœ๋ฅผ ๋งŒ๋“œ๋Š”์ง€ ๋Œ€์กฐํ•œ๋‹ค.

# check_state.py โ€” ์‹ค์ธก์น˜๋ฅผ ๋ฐ•์•„ ๋‘๊ณ  ํŒŒ์ด์ฌ ๋ชจ๋ธ๊ณผ ๋น„๊ตํ•œ๋‹ค
GDB_LFSR = [0xFF22D888, 0xA8777BA5, 0x6992F244, 0xCAF46272,
            0xC38C6DE9, 0xA1D77FA2, 0x25B7F11C, 0xC3A147A3,
            0xA402D8F2, 0xADFBD6E5, 0xAE331D05, 0x69DC8CA7,
            0x747420EA, 0xF3530624, 0x12AD67EE, 0xC8007FAB]
GDB_FSM = [0xC0B7C911, 0xF64EB4D7, 0xFF628DC0]
 
SR, SQ, TARGET = load_tables("prob")
c = Snow3G(SR, SQ)
c.initialize(list(struct.unpack("<4I", FLAG.encode()[:16])))
 
print("ํŒŒ์ด์ฌ ๋ชจ๋ธ s0..s15")
for i in range(0, 16, 4):
    print("  s%-2d " % i, " ".join("0x%08x" % v for v in c.s[i:i + 4]))
print("ํŒŒ์ด์ฌ ๋ชจ๋ธ R1 R2 R3")
print("      ", " ".join("0x%08x" % v for v in (c.R1, c.R2, c.R3)))
print()
print("gdb ์‹ค์ธก LFSR ๊ณผ ์ผ์น˜ :", c.s == GDB_LFSR)
print("gdb ์‹ค์ธก FSM  ๊ณผ ์ผ์น˜ :", [c.R1, c.R2, c.R3] == GDB_FSM)
python3 check_state.py

check_state.py ์ถœ๋ ฅ โ€” ํŒŒ์ด์ฌ ๋ชจ๋ธ์˜ LFSR 16์›Œ๋“œ์™€ FSM ์„ธ ๊ฐ’์ด gdb ๋กœ ์ฝ์€ ์‹ค์ œ ๋ฉ”๋ชจ๋ฆฌ์™€ ๋ชจ๋‘ ์ผ์น˜ํ•œ๋‹ค
check_state.py ์ถœ๋ ฅ โ€” ํŒŒ์ด์ฌ ๋ชจ๋ธ์˜ LFSR 16์›Œ๋“œ์™€ FSM ์„ธ ๊ฐ’์ด gdb ๋กœ ์ฝ์€ ์‹ค์ œ ๋ฉ”๋ชจ๋ฆฌ์™€ ๋ชจ๋‘ ์ผ์น˜ํ•œ๋‹ค

32๋ผ์šด๋“œ ์ดˆ๊ธฐํ™”๋ฅผ ๊ฑฐ์นœ ๋’ค์˜ ์ค‘๊ฐ„ ์ƒํƒœ 19๊ฐœ ์›Œ๋“œ๊ฐ€ ์ „๋ถ€ ์ผ์น˜ํ•œ๋‹ค. ์ตœ์ข… ๊ฒฐ๊ณผ ํ•˜๋‚˜๊ฐ€ ์•„๋‹ˆ๋ผ ์ค‘๊ฐ„์ด ๋งž์•„๋–จ์–ด์ง€๋‹ˆ, ์šฐ์—ฐํžˆ ๋‹ต๋งŒ ๋งž์€ ๊ฒŒ ์•„๋‹ˆ๋ผ๋Š” ๊ทผ๊ฑฐ๊ฐ€ ๋œ๋‹ค.


โœ… ์ง„์งœ ๋ฐ”์ด๋„ˆ๋ฆฌ๋กœ ํ•œ ๋ฒˆ ๋”

๋งˆ์ง€๋ง‰์€ ๋ฐฐํฌ๋œ ์‹คํ–‰ ํŒŒ์ผ์— ์ง์ ‘ ๋จน์—ฌ ๋ณด๋Š” ๊ฒƒ์ด๋‹ค. ํŒŒ์ดํ”„ ๋Œ€์‹  subprocess ๋กœ ์ธ์ž๋ฅผ ๋„˜๊ธด๋‹ค.

# verify.py
import subprocess
 
flag = "DH{F805042AC5E59FD07ABEF1E9B2EF}"
r = subprocess.run(["./prob", flag], capture_output=True, text=True)
print("Input  :", flag, "(len=%d)" % len(flag))
print("Output :", r.stdout.strip())
 
wrong = "DH{F805042AC5E59FD07ABEF1E9B2Ef}"      # ๋งˆ์ง€๋ง‰ ๊ธ€์ž ํ•˜๋‚˜๋งŒ ๋ฐ”๊พผ ๊ฒƒ
r2 = subprocess.run(["./prob", wrong], capture_output=True, text=True)
print("Input  :", wrong, "(ํ•œ ๊ธ€์ž ๋ณ€์กฐ)")
print("Output :", r2.stdout.strip())
python3 verify.py

verify.py ์ถœ๋ ฅ โ€” ๋ณต์›ํ•œ 32๊ธ€์ž๋Š” Correct! ๋ฅผ ๋‚ด๊ณ  ๋งˆ์ง€๋ง‰ ๊ธ€์ž ํ•˜๋‚˜๋งŒ ๋ฐ”๊พธ๋ฉด Wrong... ์ด ๋‚˜์˜จ๋‹ค
verify.py ์ถœ๋ ฅ โ€” ๋ณต์›ํ•œ 32๊ธ€์ž๋Š” Correct! ๋ฅผ ๋‚ด๊ณ  ๋งˆ์ง€๋ง‰ ๊ธ€์ž ํ•˜๋‚˜๋งŒ ๋ฐ”๊พธ๋ฉด Wrong... ์ด ๋‚˜์˜จ๋‹ค

ํ•œ ๊ธ€์ž๋งŒ ๋Œ€์†Œ๋ฌธ์ž๋ฅผ ๋ฐ”๊ฟ”๋„ ๋ฐ”๋กœ Wrong... ์ด๋‹ค. ์šฐ์—ฐํžˆ ํ†ต๊ณผํ•  ์—ฌ์ง€๊ฐ€ ์—†๋‹ค๋Š” ํ™•์ธ์ด๋‹ค.

๋ฐฑ์—…๋ณธ๋งŒ ๊ฐ€์ง€๊ณ ๋„ ๋‹ค์‹œ ํ”Œ๋ž˜๊ทธ๋ฅผ ๋ฝ‘์„ ์ˆ˜ ์žˆ๊ฒŒ, ๋นŒ๋“œ๋ถ€ํ„ฐ ๋Œ€์กฐ๊นŒ์ง€ ํ•œ ๋ฐฉ์— ๋„๋Š” ์Šคํฌ๋ฆฝํŠธ๋ฅผ ๋‚จ๊ฒผ๋‹ค.

#!/usr/bin/env bash
# snow (Dreamhack, Silver 1 / reversing) โ€” ํ•œ ๋ฐฉ ์žฌํ˜„.
# ๋ฐฐํฌ ๋ฐ”์ด๋„ˆ๋ฆฌ prob ํ•˜๋‚˜๋งŒ ์žˆ์œผ๋ฉด ๋œ๋‹ค. ํ…Œ์ด๋ธ”ยท์ •๋‹ต 32๋ฐ”์ดํŠธ๋ฅผ .data ์—์„œ ์ง์ ‘ ์ฝ์œผ๋ฏ€๋กœ
# ๋ณ„๋„ ์ž…๋ ฅ ํŒŒ์ผ์ด ์—†๋‹ค. ํŒŒ์ด์ฌ 3 ๋งŒ ์žˆ์œผ๋ฉด ์–ด๋””์„œ๋“  ๋ˆ๋‹ค(์™ธ๋ถ€ ํŒจํ‚ค์ง€ ์—†์Œ).
set -eu
cd "$(dirname "$(readlink -f "$0")")"
 
EXPECT=$(python3 -c "import json;print(json.load(open('../๋ฌธ์ œ.json'))['flag'])" 2>/dev/null || echo '')
 
chmod +x prob 2>/dev/null || true
 
OUT=$(timeout 300 python3 solve.py 2>&1) || true
echo "$OUT" | tail -8
 
# ํ›„๋ณด ๋ชฉ๋ก์—๋„ DH{ ๋กœ ์‹œ์ž‘ํ•˜๋Š” ๊นจ์ง„ ๋ฌธ์ž์—ด์ด ์„ž์ด๋ฏ€๋กœ ๋งˆ์ง€๋ง‰ ANSWER ์ค„์—์„œ๋งŒ ๋ฝ‘๋Š”๋‹ค.
FLAG=$(printf '%s' "$OUT" | sed -n 's/^ANSWER: //p' | tail -1)
 
# ๋ฝ‘์€ ๊ฐ’์„ ๋ฐฐํฌ ๋ฐ”์ด๋„ˆ๋ฆฌ์— ๊ทธ๋Œ€๋กœ ๋จน์—ฌ Correct! ๊ฐ€ ๋‚˜์˜ค๋Š”์ง€๊นŒ์ง€ ๋ณธ๋‹ค.
if [ -n "$FLAG" ]; then
  VERDICT=$(./prob "$FLAG" 2>&1 || true)
  echo "./prob '$FLAG' โ†’ $VERDICT"
else
  VERDICT=""
fi
 
if [ -n "$FLAG" ] && [ "$VERDICT" = "Correct!" ] && { [ -z "$EXPECT" ] || [ "$FLAG" = "$EXPECT" ]; }; then
  echo; echo "โœ… PASS  $FLAG"; exit 0
fi
echo; echo "โŒ FAIL (์–ป์€ ๊ฐ’: '${FLAG:-์—†์Œ}' / ๋ฐ”์ด๋„ˆ๋ฆฌ ํŒ์ •: '${VERDICT:-์—†์Œ}' / ๊ธฐ๋Œ€: '$EXPECT')"; exit 1
./reproduce.sh

reproduce.sh ์‹คํ–‰ ๊ฒฐ๊ณผ โ€” ํ”Œ๋ž˜๊ทธ๋ฅผ ๋ฝ‘๊ณ  ๋ฐฐํฌ ๋ฐ”์ด๋„ˆ๋ฆฌ๋กœ Correct! ๊นŒ์ง€ ํ™•์ธํ•œ ๋’ค PASS ๋กœ ๋๋‚œ๋‹ค
reproduce.sh ์‹คํ–‰ ๊ฒฐ๊ณผ โ€” ํ”Œ๋ž˜๊ทธ๋ฅผ ๋ฝ‘๊ณ  ๋ฐฐํฌ ๋ฐ”์ด๋„ˆ๋ฆฌ๋กœ Correct! ๊นŒ์ง€ ํ™•์ธํ•œ ๋’ค PASS ๋กœ ๋๋‚œ๋‹ค

๋กœ์ปฌ ํ™˜๊ฒฝ: Ubuntu 22.04 ยท x86-64 ยท Python 3.10(์™ธ๋ถ€ ํŒจํ‚ค์ง€ ์—†์Œ) ยท binutils 2.38 ์˜ objdump ยท GNU gdb 12.1. ๋ฌธ์ œ ๋ฐ”์ด๋„ˆ๋ฆฌ๋Š” for GNU/Linux 3.2.0 ๋กœ ๋นŒ๋“œ๋œ ๊ฒƒ์ด๋ผ ์š”์ฆ˜ ๋ฐฐํฌํŒ์—์„œ๋„ ๊ทธ๋Œ€๋กœ ๋ˆ๋‹ค.



๐Ÿ“ ๊ฒฐ๋ก 

ํ‘œ์ค€ ์•Œ๊ณ ๋ฆฌ์ฆ˜์€ ์ƒ์ˆ˜๋กœ ์ฐพ๋Š” ๊ฒŒ ๋น ๋ฅด๋‹ค

๋””์Šค์–ด์…ˆ๋ธ”๋ฆฌ๋ฅผ ์œ„์—์„œ๋ถ€ํ„ฐ ๋‹ค ์ฝ์„ ํ•„์š”๋Š” ์—†์—ˆ๋‹ค. MULxPOW ์˜ ์ง€์ˆ˜ 23, 245, 48, 239 ์™€ ์ƒ์ˆ˜ 0xa9 โ€” ์ด ์กฐํ•ฉ ํ•˜๋‚˜๊ฐ€ "SNOW 3G ๋‹ค"๋ฅผ ํ™•์ •ํ•ด ์คฌ๋‹ค.

AES S-box ๋Š” ์—ฌ๋Ÿฌ ์•Œ๊ณ ๋ฆฌ์ฆ˜์ด ๋นŒ๋ ค ์“ฐ๋‹ˆ ๊ทธ๊ฒƒ๋งŒ์œผ๋กœ๋Š” ๋ถ€์กฑํ•˜๋‹ค. ๋ฐ˜๋ฉด alpha ๊ณฑ์…ˆ์˜ ์ง€์ˆ˜ ๋„ค ๊ฐœ๋Š” ๊ทธ ์•Œ๊ณ ๋ฆฌ์ฆ˜์—๋งŒ ์žˆ๋‹ค. ๋‚ฏ์„  ์•”ํ˜ธ ๋ฃจํ‹ด์„ ๋งŒ๋‚˜๋ฉด ๊ฐ€์žฅ ํŠน์ดํ•œ ์ƒ์ˆ˜๋ถ€ํ„ฐ ๊ฒ€์ƒ‰ํ•˜๋Š” ๊ฒŒ ํ•จ์ˆ˜ ์ด๋ฆ„ ์—†๋Š” ๋ฐ”์ด๋„ˆ๋ฆฌ์—์„œ ์ œ์ผ ๋น ๋ฅธ ๊ธธ์ด๋‹ค.

์ถœ๋ ฅ์„ ๋ฒ„๋ฆฌ๋Š” ์ง€์ ์ด ๊ณง ๊ณต๊ฒฉ๋ฉด์ด๋‹ค

์ด ๋ฌธ์ œ์˜ ๊ธ‰์†Œ๋Š” SNOW 3G ์ž์ฒด๊ฐ€ ์•„๋‹ˆ๋ผ, 32๋น„ํŠธ๋ฅผ ๋ฝ‘์•„ 1๋น„ํŠธ๋งŒ ์“ด ์„ค๊ณ„์˜€๋‹ค. ์›Œ๋“œ๋งˆ๋‹ค ๋ฏธ์ง€์ˆ˜๊ฐ€ 1๋น„ํŠธ๋กœ ์ค„์–ด๋“œ๋‹ˆ ์ž๊ธฐ์ฐธ์กฐ ๊ณ ๋ฆฌ๊ฐ€ 8๋น„ํŠธ๋กœ ์ ‘ํžŒ๋‹ค.

์•”ํ˜ธ ์•Œ๊ณ ๋ฆฌ์ฆ˜์ด ์•„๋ฌด๋ฆฌ ํŠผํŠผํ•ด๋„ ๊ทธ๊ฑธ ์“ฐ๋Š” ์ฝ”๋“œ๊ฐ€ ์ •๋ณด๋ฅผ ๋ฒ„๋ฆฌ๋ฉด ๊ทธ ์ž๋ฆฌ๊ฐ€ ํƒ์ƒ‰ ๊ณต๊ฐ„์ด ๋œ๋‹ค. ์‹ค๋ฌด์—์„œ๋„ "ํ•ด์‹œ์˜ ์•ž 4๋ฐ”์ดํŠธ๋งŒ ์“ด๋‹ค", "๋‚œ์ˆ˜์˜ ํ•˜์œ„ ๋น„ํŠธ๋งŒ ์“ด๋‹ค" ๊ฐ™์€ ์ ˆ์•ฝ์ด ๊ฐ™์€ ๋ฐฉ์‹์œผ๋กœ ๋ฌด๋„ˆ์ง„๋‹ค.

ํ›„๋ณด๊ฐ€ ์‚ด์•„๋‚จ์•˜๋‹ค๋Š” ๊ฒƒ ์ž์ฒด๋Š” ์ฆ๊ฑฐ๊ฐ€ ์•„๋‹ˆ๋‹ค

์ž๊ธฐ๋ฌด๋ชจ์ˆœ ๊ฒ€์‚ฌ๋งŒ์œผ๋กœ 256๊ฐœ ์ค‘ 4๊ฐœ๊ฐ€ ๋‚จ์•˜๋‹ค. ์ž˜๋ชป๋œ ๋ชจ๋ธ(์ดˆ๊ธฐํ™” ๊ผฌ๋ฆฌ ๋ˆ„๋ฝ, ๋น…์—”๋””์–ธ IV)์—์„œ๋„ 2~3๊ฐœ๋Š” ๋‚จ์•˜๋‹ค. "๋ช‡ ๊ฐœ ์‚ด์•„๋‚จ์•˜๋‹ค"๋Š” ์‚ฌ์‹ค์€ ๋ชจ๋ธ์ด ๋งž๋‹ค๋Š” ๋ณด์ฆ์ด ์ „ํ˜€ ์•ˆ ๋œ๋‹ค.

ํŒ์ •์€ ๋ฐ–์—์„œ ์˜จ ๋…๋ฆฝ ๊ธฐ์ค€์ด์–ด์•ผ ํ•œ๋‹ค. ์—ฌ๊ธฐ์„œ๋Š” printable ์—ฌ๋ถ€, ์ •๋ฐฉํ–ฅ ์žฌํ˜„, ๊ทธ๋ฆฌ๊ณ  ์‹ค์ œ ๋ฐ”์ด๋„ˆ๋ฆฌ์˜ Correct! ์…‹์ด์—ˆ๋‹ค.

IV ๋ฅผ ์‚ฌ์šฉ์ž ์ž…๋ ฅ์œผ๋กœ ๋‘๋ฉด ์žฌํ˜„์„ฑ์ด ์‚ฌ๋ผ์ง„๋‹ค

๋ฐฉ์–ด ๊ด€์ ์œผ๋กœ ์˜ฎ๊ธฐ๋ฉด ์ด ๋ฌธ์ œ ์ฝ”๋“œ๋Š” IV ๋ฅผ ๊ฒ€์ฆ ์—†์ด ์‚ฌ์šฉ์ž ์ž…๋ ฅ์—์„œ ๊ฐ€์ ธ์˜จ๋‹ค. ์ง„์งœ ์„œ๋น„์Šค๋ผ๋ฉด IV ๋Š” ๋งค๋ฒˆ ์ƒˆ๋กœ ๋ฝ‘์•„ ์•”ํ˜ธ๋ฌธ๊ณผ ํ•จ๊ป˜ ์ €์žฅํ•˜๊ฑฐ๋‚˜, ์ตœ์†Œํ•œ ์นด์šดํ„ฐ๋กœ ๊ด€๋ฆฌํ•ด์•ผ ํ•œ๋‹ค.

๊ฐ™์€ IV ๋ฅผ ์žฌ์‚ฌ์šฉํ•˜๋ฉด ํ‚ค์ŠคํŠธ๋ฆผ์ด ๊ทธ๋Œ€๋กœ ๋ฐ˜๋ณต๋˜๊ณ , ์ง€๊ธˆ์ฒ˜๋Ÿผ IV ๋ฅผ ๊ณต๊ฒฉ์ž๊ฐ€ ๊ณ ๋ฅผ ์ˆ˜ ์žˆ์œผ๋ฉด ํ‚ค์ŠคํŠธ๋ฆผ์„ ์›ํ•˜๋Š” ๋ฐฉํ–ฅ์œผ๋กœ ์œ ๋„ํ•  ์ˆ˜ ์žˆ๋‹ค. ์ŠคํŠธ๋ฆผ ์•”ํ˜ธ์—์„œ nonce ์žฌ์‚ฌ์šฉ์ด ์น˜๋ช…์ ์ธ ์ด์œ ๊ฐ€ ์ด๊ฒƒ์ด๋‹ค.

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

Comments

๋Œ“๊ธ€

0๊ฐœ

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

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

Related

๊ด€๋ จ ๊ธ€

3๊ฐœ
[๐Ÿฅˆ 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 +5
[๐Ÿฅˆ Silver 3] srand(0xBEEF) ํ•˜๋‚˜๋กœ 6MB ์‚ฌ์ง„์„ ๋˜์ฐพ๋‹ค โ€” DreamHack photographer ํ’€์ด
blog

[๐Ÿฅˆ Silver 3] srand(0xBEEF) ํ•˜๋‚˜๋กœ 6MB ์‚ฌ์ง„์„ ๋˜์ฐพ๋‹ค โ€” DreamHack photographer ํ’€์ด

BMP ํ•œ ์žฅ์„ ํ†ต์งธ๋กœ ๋ฐ”๊ฟ” ๋†“์€ 26KB์งœ๋ฆฌ C++ ๋ฐ”์ด๋„ˆ๋ฆฌ. ์‹œ๋“œ๊ฐ€ time(NULL)์ด ์•„๋‹ˆ๋ผ ์ƒ์ˆ˜ 0xBEEF๊ณ , ๋ฐ”์ดํŠธ๋งˆ๋‹ค rand()๋ฅผ ์ •ํ™•ํžˆ ํ•œ ๋ฒˆ์”ฉ๋งŒ ์“ฐ๋ฉฐ, ์„ธ ๊ฐˆ๋ž˜ ๋ณ€ํ™˜์ด ๋ชจ๋‘ ๊ฐ€์—ญ์ด๋‹ค. ๊ทธ ์„ธ ์กฐ๊ฑด์ด ๋งž์•„๋–จ์–ด์ ธ์„œ ์—ญํ•จ์ˆ˜๋ฅผ ๊ฐ™์€ ์ˆœ์„œ๋กœ ํ•œ ๋ฒˆ์”ฉ ๊ฑธ๋ฉด 6,220,854๋ฐ”์ดํŠธ๊ฐ€ ๊ทธ๋Œ€๋กœ ๋Œ์•„์˜จ๋‹ค.
#dreamhack#ctf#reversing+5
2026-08-17#dreamhack +5
[๐Ÿฅˆ Silver 2] Rust ํฌ๋ž™๋ฏธ์˜ ๋น„ํŠธ ์น˜ํ™˜์„ ๊ฑฐ๊พธ๋กœ ๋Œ๋ ค 64๊ธ€์ž ์ž…๋ ฅ ๋ณต์› โ€” DreamHack CrabME ํ’€์ด
blog

[๐Ÿฅˆ Silver 2] Rust ํฌ๋ž™๋ฏธ์˜ ๋น„ํŠธ ์น˜ํ™˜์„ ๊ฑฐ๊พธ๋กœ ๋Œ๋ ค 64๊ธ€์ž ์ž…๋ ฅ ๋ณต์› โ€” DreamHack CrabME ํ’€์ด

Rust ๋กœ ๋นŒ๋“œ๋œ ํฌ๋ž™๋ฏธ. ์ž…๋ ฅ์€ 64๊ธ€์ž ์†Œ๋ฌธ์ž hex ๋กœ ๊ณ ์ •๋ผ ์žˆ๊ณ , ๋‘ ๊ธ€์ž์”ฉ ๋ฌถ์€ 32๋ฐ”์ดํŠธ๋ฅผ flagchecker ๊ฐ€ "๋น„ํŠธ ์น˜ํ™˜ โ†’ XOR 0x63 โ†’ +0x22" ์„ธ ๋‹จ๊ณ„๋กœ ๋ฐ”๊ฟ” .rodata ์— ๋ฐ•ํžŒ ์ƒ์ˆ˜ 32๊ฐœ์™€ ๋น„๊ตํ•œ๋‹ค. ์„ธ ๋‹จ๊ณ„๊ฐ€ ์ „๋ถ€ ๋ฐ”์ดํŠธ ๋‹จ์œ„ ์ „๋‹จ์‚ฌ๋ผ ๋ธŒ๋ฃจํŠธํฌ์Šค ์—†์ด ๊ทธ๋Œ€๋กœ ์—ญ์‚ฐ๋˜๊ณ , ๋‚˜์˜จ 64๊ธ€์ž๊ฐ€ ๊ณง ํ”Œ๋ž˜๊ทธ ๋ณธ๋ฌธ์ด๋‹ค. objdump ๋กœ ์น˜ํ™˜ํ‘œ๋ฅผ ์œ ๋„ํ•˜๊ณ  gdb ๋กœ ๋Ÿฐํƒ€์ž„์—์„œ ๊ฐ™์€ ๊ฐ’์ด ๋‚˜์˜ค๋Š”์ง€ ํ™•์ธํ–ˆ๋‹ค.
#dreamhack#ctf#reversing+6
2026-07-26#dreamhack +5