๋ฌธ์ : DreamHack โ Rusty Gyul ๋ถ๋ฅ: Reversing ๋์ด๋: ๐ฅ Bronze 3 FLAG:
B1N4RY{Z2FtZ3l1bG11a2dvc2lwZGE=}
๋ฐ์ด๋๋ฆฌ ํ๋๊ฐ ๋๋ ์ฃผ์ด์ง๋ค. ์คํํ๋ฉด ๊ตต์ = ๋ฐฐ๋์ ํจ๊ป Gyullllllllll!!!!! ๋ฅผ ์ธ์น๊ณ
ํ๋๊ทธ๋ฅผ ์
๋ ฅ๋ฐ์ ๋ค, ํ๋ฆฌ๋ฉด [-] Wrong flag. Try again. ์ ๋ฑ๋๋ค. ์๋ฒ๋ ์๊ณ ํํธ๋ ์๋ค.
์ด ์์ ์ ๋ต์ ํ๋ณํ๋ ๋ก์ง์ด ํต์งธ๋ก ๋ค์ด ์์ผ๋, ๊ทธ ํ๋ณ์ ๊ฑฐ๊พธ๋ก ๋๋ฆฌ๋ฉด ํ๋๊ทธ๊ฐ ์์ ์กํ๋ค๋ ๋ป์ด๋ค.
Rust ๋ก ์ง์ฌ ์ฌ๋ณผ์ด ์ ๋ถ stripped ๋ ๋ฐ์ด๋๋ฆฌ๋ผ ์ฒ์์ ํจ์ ์ด๋ฆ ํ๋ ์ ๋ณด์ด์ง๋ง, ๊ฒ์ฌ ๋ก์ง ์์ฒด๋ ํ๋ฌดํ ๋งํผ ๋จ์ํ๋ค. ์ด ๊ธ์ "๊ทธ ๋จ์ํ ํ ์ค"์ ์ด์ ๋ธ๋ฆฌ์์ ์ฐพ์ ๋ค์ด๊ฐ ํ์ธํ๊ณ ๋๋๋ฆฌ๋ ๊ณผ์ ์ด๋ค.
๋ฌธ์ ๊ฐ์
| ํญ๋ชฉ | ๋ด์ฉ |
|---|---|
| ๋ฌธ์ ๋ช | Rusty Gyul |
| ๋์ด๋ | ๐ฅ Bronze 3 |
| ๋ถ๋ฅ | Reversing |
| ์ ๊ณต ํ์ผ | rusty_gyul (x86-64 ELF, PIE, stripped) |
| ํต์ฌ ๊ธฐ๋ฒ | stripped Rust ๋ฐ์ด๋๋ฆฌ ์ ์ ๋ถ์ ยท ์คํ ์์ key ์ถ์ถ ยท XOR ์ญ์ฐ |
Rusty Gyul ์ ๋๋ฆผํต์ "๊ทค(gyul)" ํ
๋ง ๋ฆฌ๋ฒ์ฑ ์๋ฆฌ์ฆ ์ค ํ๋๋ค. Packing Tangerines,
Gyul Bomb ์ฒ๋ผ ์ด๋ฆ๋ง ๊ท์ฝ๊ณ ์์ ํ๋ฒํ crackme ์ธ๋ฐ, ์ด๋ฒ์ ๊ทธ crackme ๋ฅผ Rust ๋ก ์ปดํ์ผํด
์ฌ๋ณผ๊ณผ ๋๋ฒ๊ทธ ์ ๋ณด๋ฅผ ๊ฑท์ด๋ธ ๊ฒ ์ ๋ถ๋ค. Rust ๋ผ๊ณ ๊ฒ๋จน์ ํ์๋ ์๋ค โ ์ปดํ์ผ๋ฌ๊ฐ ๋ง๋ค์ด๋ด๋
๊ป๋ฐ๊ธฐ(๋ฐํ์ ๋ถํธ์คํธ๋ฉ, UTF-8 ์ฒ๋ฆฌ)๋ง ๊ฑท์ด๋ด๋ฉด ๊ฒ์ฌ ์๊ณ ๋ฆฌ์ฆ์ C ๋ก ์ง ๊ฒ๊ณผ ๋ค๋ฅด์ง ์๋ค.
๐ฌ ์ ์ฐฐ
๋จผ์ ํ์ผ ์ ์ฒด์ ์์ ๋ฐํ ๋ฌธ์์ด๋ถํฐ ๋ณธ๋ค.
์ด ๊ธ์ ๋ช ๋ น์ ๋ชจ๋
extracted/์์ ์คํํ๋ค.
file rusty_gyul; strings -n 6 rusty_gyul | grep -iE 'Input the flag|Correct! The|Wrong flag|Gyul|Enjoy'
ELF 64-bit ... pie executable ... strippedโ PIE ๋ผ ์ฃผ์๋ ๋ก๋ ์๋ง๋ค ๋ฐ๋๊ณ , ์ฌ๋ณผ ํ ์ด๋ธ์ ์๋ค.- ๋ฌธ์์ด์
Input the flag:,[-] Wrong flag. Try again.,[+] Correct! The flag is yours.๊ฐ ๋ณด์ธ๋ค. ํ์ ๋ถ๊ธฐ๊ฐ ์ด ์ธ ๋ฌธ์์ด ๊ทผ์ฒ์ ์์ ๊ฒ์ด๋ค. src/main.rs๊ฐ์ Rust ํ์ ๋ ๋จ์ ์์ด ์์ค ์ธ์ด๊ฐ Rust ์์ ํ์ธํ ์ ์๋ค.
๋ฉ์์ง๋ง ๋ด์ ์ด๋ค ๊ฐ๊ณผ ๋น๊ตํ๋์ง ์ ์ ์๋ค. ํ๋ณ ์ฝ๋๋ก ์ง์ ๋ค์ด๊ฐ์ผ ํ๋ค.
๐ณ๏ธ ์ฝ์ง ๊ธฐ๋ก โ strcmp ๋ฅผ ์ฐพ๋ค๊ฐ ํํ, main ์ ๊ป๋ฐ๊ธฐ์๋ค
์ฒ์์ "์ด๋๊ฐ์์ ๋ด ์
๋ ฅ์ ์ ๋ต ๋ฌธ์์ด๊ณผ strcmp/memcmp ํ๊ฒ ์ง" ํ๊ณ ๋์ ๋ถ์๋ถํฐ ๋ถ์๋ค.
๊ทธ๋ฐ๋ฐ ltrace ๋ก ๋๋ ค๋ด๋ ๋น๊ต ํจ์ ํธ์ถ์ด ํ๋๋ ์ ์กํ๋ค. Rust ๋ == ๋น๊ต๋ฅผ ๋ผ์ด๋ธ๋ฌ๋ฆฌ
ํธ์ถ์ด ์๋๋ผ ์ธ๋ผ์ธ ๋ฐ์ดํธ ๋ฃจํ๋ก ํผ์ณ ์ปดํ์ผํ๊ธฐ ๋๋ฌธ์, libc ์ฌ๋ณผ ํํน์ผ๋ก๋ ์๋ฌด๊ฒ๋ ์ ๋์จ๋ค.
(์ด ์ง์ ์์ ์ธ ๋ฒ์ฏค ๋ค๋ฅธ ๊ธธ๋ก ์๋ค.)
๊ทธ๋ค์์ main ์ ๋ดค๋๋ฐ, ์ด๊ฒ๋ ํจ์ ์ด์๋ค. ์ ์ ๋ถ์๊ธฐ๊ฐ main ์ด๋ผ๊ณ ํ์ํ๋ ํจ์๋ ๊ณ ์
์ด ์ ๋๋ค.
; main (0x165e0) โ ์ง์ง ๋ก์ง์ด ์๋ค
mov rdx, rsi ; argv
movsxd rsi, edi ; argc
lea rdi, [0x16099] ; <-- ์ง์ง main ํด๋ก์ ์ฃผ์๋ฅผ ๋๊ธด๋ค
xor ecx, ecx
jmp 0x16457 ; std::rt::lang_start(...)Rust ํ๋ก๊ทธ๋จ์ main ์ ์ฌ์ฉ์ ์ฝ๋๊ฐ ์๋๋ผ std::rt::lang_start ๋ก ๋์ด๊ฐ๋ ์์ ๋ํผ๋ค.
์ฐ๋ฆฌ๊ฐ ์ง ์ง์ง main ์ ํจ์ ํฌ์ธํฐ๋ก ์ ๋ฌ๋๋ ํด๋ก์ (์ฌ๊ธฐ์ 0x16099)์ ๋ค์ด ์๋ค.
lea rdi, [0x16099] ์ด ํ ์ค์ด "์ฌ๊ธฐ๊ฐ ์ง์ง ์์์ "์ด๋ผ๋ ์ด์ ํ์๋ค. ์ฌ๊ธธ ๋์น๊ณ ๋ํผ๋ง
๋ค์ฌ๋ค๋ณด๋๋ผ ์๊ฐ์ ๋ฒ๋ ธ๋ค.
๐ฃ ์ง์ง ๊ฒ์ฌ ๋ฃจํด ์ฐพ๊ธฐ
main ๋ํผ๊ฐ lang_start ์ ๋๊ธฐ๋ ํจ์ ํฌ์ธํฐ 0x16099 ๊ฐ ์ค์ ํ๋ก๊ทธ๋จ ๋ณธ์ฒด๋ค.
์ด ํจ์๋ฅผ ๋ฐ๋ผ๊ฐ๋ฉด ๋ฐฐ๋ ์ถ๋ ฅ โ ํ ์ค ์
๋ ฅ โ ํ์ ๊น์ง ์ ๋ถ ๋ค์ด ์๋ค. ์
๋ ฅ์ ์ฝ์ ์งํ ๋ ๊ฐ์
๋น์ทํ ๋ฃจํ๊ฐ ๋๋๋ฐ, ๋ ๋ค ๊ฐ์ ์๋ธ๋ฃจํด(0x1653b)์ ํธ์ถํ๋ค. ๊ทธ ์๋ธ๋ฃจํด์ ์ด์ด๋ณด๋ฉด ์ ์ฒด๊ฐ ๋ณด์ธ๋ค.
; fcn 0x1653b โ char::is_whitespace
lea ecx, [rdi - 9]
cmp ecx, 0x18
... ; 0x09..0x0d(ํญ/๊ฐํ๋ฅ), 0x20(๊ณต๋ฐฑ),
cmp edi, 0x1680 ; ๊ทธ๋ฆฌ๊ณ ์ ๋์ฝ๋ ๊ณต๋ฐฑ(0x1680, 0x2000.., 0x3000 โฆ)
cmp edi, 0x30000x09~0x0d, 0x20, 0x1680, 0x3000 โฆ ๋ฑ ๋ด๋ ๊ณต๋ฐฑ ํ์ ์ด๋ค. ์ฆ ๋ ๋ฃจํ๋ ์
๋ ฅ ์์ชฝ๊ณผ
๋ค์ชฝ์์ ๊ณต๋ฐฑ์ ๊ฑท์ด๋ด๋ str::trim() ์ด๋ค. ์ฌ์ฉ์๊ฐ ์ํฐ๋ฅผ ์น๋ฉฐ ๋จ๊ธด ๊ฐํ(\n)์ ๋ผ์ด๋ด๋
์ ํ์ ์ธ ํจํด์ด๋ค. ์ ๋ฆฌํ๋ฉด ํ๋ฆ์ ์ด๋ ๋ค.
- ํ ์ค ์ ๋ ฅ์ ๋ฐ๋๋ค.
input.trim()โ ์๋ค ๊ณต๋ฐฑ/๊ฐํ ์ ๊ฑฐ.- trim ํ ๊ธธ์ด๊ฐ ์ ํํ 32 ์ธ์ง ๋ณธ๋ค.
- 32๋ฐ์ดํธ๋ฅผ ํ ๋ฐ์ดํธ์ฉ ๊ฒ์ฌํ๋ค.
ํต์ฌ์ 4๋ฒ์ด๋ค. 0x16099 ํจ์์ ํ์ ๊ตฌ๊ฐ(0x16302~)์ objdump ๋ก ์๋ผ, ์ด๋ค ๋ช
๋ น์ด ๋ฌด์จ
์ผ์ ํ๋์ง ์ฃผ์์ ๋ฌ์ ๋ณด๋ฉด ํ์ ์ ์ ์ฒด๊ฐ ๊ทธ๋๋ก ๋๋ฌ๋๋ค.
objdump -d --no-show-raw-insn --start-address=0x16302 --stop-address=0x16342 rusty_gyul \
| sed -E -f notes.sed
์ฝ์ด๋ณด๋ฉด ์ด๋ ๋ค.
movaps -0x101b1(%rip),%xmm0/movaps -0x101ed(%rip),%xmm0โ.rodata๋ ๊ณณ(0x6160,0x6130)์์ 16๋ฐ์ดํธ์ฉ ์ฝ์ด ์คํ(rsp+0x30,rsp+0x40)์ ์ด์ด๋ถ์ธ๋ค. ์ด๊ฒ 32๋ฐ์ดํธ key ๋ค.cmp $0x20,%rbpโ trim ๋ ์ ๋ ฅ ๊ธธ์ด๊ฐ0x20(=32)์ด ์๋๋ฉด ๋ฐ๋ก ์ค๋ต์ผ๋ก ์ ํ.- ๊ทธ๋ฆฌ๊ณ ๋ฃจํ:
loop:
cmp $0x20,%rax ; i == 32 ์ด๋ฉด -> ์ ๋ต ์ถ๋ ฅ
je correct
mov 0x30(%rsp,%rax,1),%cl ; cl = key[i]
xor (%rdx,%rax,1),%cl ; cl ^= input[i]
inc %rax
cmp $0x55,%cl ; (key[i] ^ input[i]) == 0x55 ?
je loop ; ๋ง์ผ๋ฉด ๋ค์ ๊ธ์, ํ๋ฆฌ๋ฉด ์ค๋ต์ฆ ๊ฒ์ฌ์์ ๋จ ํ๋๋ค โ ๋ชจ๋ i(0..31)์ ๋ํด key[i] ^ input[i] == 0x55.
XOR ์ ์๊ธฐ ์ญ์์ด๋, ์ด๊ฑธ ๋ค์ง์ผ๋ฉด ๊ณง๋ฐ๋ก ์ ๋ต์ด ๋๋ค: input[i] = key[i] ^ 0x55.

key ๋ฅผ ์ด๋ฃจ๋ ๋ ๋ธ๋ก์ ์์๊ฐ ๋ค๋ฐ๋์ด ์ค๋ฆฐ๋ค๋ ์ ๋ง ์ฃผ์ํ๋ฉด ๋๋ค. ์คํ์์ ๋ฎ์ ์ฃผ์(rsp+0x30)์
๋จผ์ ์ค๋ฆฌ๋ ๊ฑด 0x6160 ์ชฝ 16๋ฐ์ดํธ(= key ์๋ถ๋ถ), ๊ทธ๋ค์ rsp+0x40 ์ 0x6130 ์ชฝ 16๋ฐ์ดํธ(= key ๋ท๋ถ๋ถ)๋ค.
๐งช ๋ฐํ์์ผ๋ก ํ ๋ฒ ๋ ํ์ธ
์ ์ ๋ถ์๋ง ๋ฏฟ๊ณ ๋์ด๊ฐ์ง ์๊ณ , gdb ๋ก ์ค์ ์คํ ์ค์ ๊ทธ ์คํ์
๊ณผ ๊ฐ์ด ๋ง๋์ง ํ์ธํ๋ค.
PIE ๋ผ ๋ก๋ ์ฃผ์๊ฐ ๋งค๋ฒ ๋ฐ๋๋ฏ๋ก set disable-randomization on ์ผ๋ก ๊ณ ์ ํ ๋ค, ๊ฒ์ฌ ์ง์
์
(0x16322)๊ณผ per-char ๋น๊ต(0x1633d)์ ๋ธ๋ ์ดํฌํฌ์ธํธ๋ฅผ ๊ฑธ๊ณ ์ ๋ต ํ๋๊ทธ๋ฅผ ์
๋ ฅ์ผ๋ก ๋ฃ์ด๋ดค๋ค.
gdb -q -batch -x check.gdb --args ./rusty_gyul < input.txt
rbp = 32โ trim ๋ ๊ธธ์ด๊ฐ 32๋ก, ๊ธธ์ด ๊ฒ์ฌ๋ฅผ ํต๊ณผํ๋ค.- ์คํ(
rsp+0x30)์์ ๋คํํ 32๋ฐ์ดํธ๊ฐ17 64 1b 61 07 0c 2e 0f โฆโ objdump ๋ก ์ ์ ์ผ๋ก ์ง์.rodata๊ฐ๊ณผ ์ ํํ ์ผ์นํ๋ค. key ๊ฐ ์คํ ์์ ์ ์คํ ์ด๋์ ์ค๋ฆฌ๋์ง๊น์ง ๋์ผ๋ก ํ์ธ๋ ์ ์ด๋ค. key[i] ^ input[i]๊ฐi=0,1,2 โฆ๋ชจ๋0x55โ ๊ฒ์ฌ์์ด ์ค์ ๋ก ๊ทธ๋ ๊ฒ ๋์ํ๋ค.
์ ์ ์ผ๋ก ์ฝ์ด๋ธ ๊ตฌ์กฐ๊ฐ ๋ฐํ์์์๋ ๊ทธ๋๋ก์๋ค. ์ด์ ๋๋๋ฆฌ๊ธฐ๋ง ํ๋ฉด ๋๋ค.
๐ฏ ํ์ด โ key ๋ฅผ ๋ฝ์ 0x55 ๋ก ๋XOR
๋ฐ์ด๋๋ฆฌ์์ .rodata ์ ๋ ๋ธ๋ก์ ๊ทธ๋๋ก ์ฝ์ด, ์คํ์ ์ค๋ฆฌ๋ ์์(0x6160 โ 0x6130)๋๋ก
์ด์ด๋ถ์ธ 32๋ฐ์ดํธ key ๋ฅผ ๋ง๋ค๊ณ ๊ฐ ๋ฐ์ดํธ๋ฅผ 0x55 ๋ก XOR ํ๋ค. .rodata ๋ ํ์ผ ์คํ์
๊ณผ
๊ฐ์์ฃผ์๊ฐ ๊ฐ์ ๊ตฌ๊ฐ(๋ ๋ค 0x6100 ์์)์ด๋ผ ํ์ผ์์ ๋ฐ๋ก ์๋ผ ์ฐ๋ฉด ๋๋ค.
# solve.py
BIN = "rusty_gyul"
XOR = 0x55
data = open(BIN, "rb").read()
# ์คํ์ ์ค๋ฆฌ๋ ์์: 0x6160(์ 16B) + 0x6130(๋ค 16B)
key = data[0x6160:0x6160 + 16] + data[0x6130:0x6130 + 16]
flag = bytes(b ^ XOR for b in key)
print(f"[*] key = {key.hex()}")
print(f"[*] flag = {flag.decode()}")
import base64
inner = flag[flag.index(b"{") + 1: flag.index(b"}")]
print(f"[*] inner = {base64.b64decode(inner).decode()} # (base64 decode)")
ํ๋๊ทธ๊ฐ ๊ทธ๋๋ก ๋จ์ด์ง๋ค.
B1N4RY{Z2FtZ3l1bG11a2dvc2lwZGE=}์ฌ๋ฏธ์๋ ๊ฑด ํ๋๊ทธ ์์ชฝ Z2FtZ3l1bG11a2dvc2lwZGE= ๋ฅผ base64 ๋ก ํ ๋ฒ ๋ ํ๋ฉด
gamgyulmukgosipda โ "๊ฐ๊ทค ๋จน๊ณ ์ถ๋ค" ๊ฐ ๋์จ๋ค๋ ์ ์ด๋ค. ๋ฌธ์ ์ ๋ชฉ์ด ์ Rusty Gyul ์ธ์ง
์ ๊ฒ ๊ฐ์ ์์ํ ์ฅ๋์ด๋ค.
โ ๊ฒ์ฆ
๋ณต์ํ ๊ฐ์ด ์ง์ง ์ ๋ต์ธ์ง, ๋ก์ปฌ ๋ฐ์ด๋๋ฆฌ์ ๊ทธ๋๋ก ๋จน์ฌ ํ์ธํ๋ค. ํ์ดํ(echo | ./bin)๋
ํ๊ฒฝ์ ๋ฐ๋ผ ์ค๋์ํ ์ ์์ด subprocess ๋ก ๋ฃ๋๋ค.
# verify.py
import subprocess
flag = "B1N4RY{Z2FtZ3l1bG11a2dvc2lwZGE=}"
r = subprocess.run(["./rusty_gyul"], input=flag + "\n",
capture_output=True, text=True)
print("Input :", flag)
print("Output:")
print(r.stdout.strip())
[+] Correct! The flag is yours. ๊ทธ๋๋ก ๋ฌ๋ค. ๋๋ฆผํต์ ์ ์ถํด๋ ์ ๋ต ์ฒ๋ฆฌ๋๋ค.
๐ก๏ธ ์ ๋ฆฌ & ๋ฐฉ์ด ๊ด์
์ด ๋ฌธ์ ๊ฐ ์ฃผ๋ ๊ตํ์ ๋ ๊ฐ์ง๋ค.
๋ฆฌ๋ฒ์ ์
์ฅ โ Rust ๋ฐ์ด๋๋ฆฌ๋ผ๊ณ ์ ๊ทผ์ด ๋ฌ๋ผ์ง์ง ์๋๋ค. ์ฌ๋ณผ์ด ์์ด๋ (1) ์ถ๋ ฅ ๋ฌธ์์ด ๊ทผ์ฒ์
๋ถ๊ธฐ, (2) main ์ด lang_start ์ ๋๊ธฐ๋ ํจ์ ํฌ์ธํฐ, ์ด ๋ ์ด์ ํ๋ง ์ก์ผ๋ฉด ์ฌ์ฉ์ ๋ก์ง์ผ๋ก
๋ฐ๋ก ๋ด๋ ค๊ฐ ์ ์๋ค. libc ํํน(ltrace)์ด ๋น์ด ์์ผ๋ฉด "๋น๊ต๊ฐ ์ธ๋ผ์ธ๋๊ตฌ๋" ํ๊ณ ์ ์ ๋ถ์์ผ๋ก
์ ํํ๋ฉด ๋๋ค. ๊ทธ๋ฆฌ๊ณ ์ ์ ์ผ๋ก ์ง์ ์คํ์
ยท์์๋ gdb ๋ฐํ์์ผ๋ก ํ ๋ฒ ๋ ํ์ธํ๋ ์ต๊ด์ด,
"๋ด๊ฐ ์๋ชป ์ฝ์ ๊ฒ"๊ณผ "์ง์ง ๊ทธ๋ฐ ๊ฒ"์ ๊ฐ๋ฅธ๋ค.
๋ฐฉ์ด(๋ฌธ์ ์ถ์ ) ์
์ฅ โ ์ ๋ต์ ์์๋ก ๊ทธ๋๋ก ๋ค๊ณ ์์ผ๋ฉด(์ค๋ น XOR ํ ๊ฒน์ ์์๋) ๋ฐ์ด๋๋ฆฌ๋ฅผ
๊ฐ์ง ์ฌ๋์๊ฒ ์๋ฌด ๋น๋ฐ๋ ์๋๋ค. ์ฌ๊ธฐ์ key 32๋ฐ์ดํธ๊ฐ .rodata ์ ๊ทธ๋๋ก ์๊ณ XOR ์์๋
0x55 ํ ๋ฐ์ดํธ๋ผ, ๊ฒ์ฌ ๋ฃจํ ํ ๋์ ์ ๋ถ ๋ณต์๋๋ค. ์ค์ ๋ก ๊ฐ์ ์จ๊ธฐ๋ ค๋ฉด ํด๋ผ์ด์ธํธ ์ธก ์์ ๋น๊ต๊ฐ
์๋๋ผ ์๋ฒ ๊ฒ์ฆ(์
๋ ฅ์ ์๋ฒ๋ก ๋ณด๋ด ํ์ )์ด๋, ์ต์ํ ์
๋ ฅ์์ ํ์ํ ํค๋ก๋ง ํ๋ฆฌ๋ ๊ตฌ์กฐ์ฌ์ผ ํ๋ค.
crackme ๋ ์๋ "์จ๊ธด ์ฒ"์ผ ๋ฟ, ๋ฐ์ด๋๋ฆฌ ์์ ๋น๊ต๋ ์ธ์ ๋ ๋ค์งํ๋ค.
Comments
๋๊ธ
๋๊ธ์ ๋จ๊ธฐ๋ ค๋ฉด ๋ก๊ทธ์ธ์ด ํ์ํด์. (๋ค์ด๋ฒ ยท ๊ตฌ๊ธ ๊ณ์ )
๋๊ธ ๋ถ๋ฌ์ค๋ ์คโฆ