서론
원격 코드 실행 (Remote Code Execution) : 원격에서 곧바로 공격할 수 있는 취약점, 사전에 예방할 수 있는 방법이 없다.
이번 강의에서는 공격을 어렵게 하기 위한 보안 매커니즘인 샌드박스 (Sandbox)와 이에 속하는 기술인 SECCOMP를 알아보고, 해당 기술이 적용된 바이너리의 분석을 도와주는 도구인 seccomp-tools에 대해서 배울 수 있다.
Sandbox
샌드박스 (Sandbox) ; 외부의 공격으로부터 시스템을 보호하기 위해 설계된 기법
Allow List와 Deny List 두 가지를 선택해 적용할 수 있으며, 애플리케이션의 기능을 수행하는데 있어서 꼭 필요한 시스템 콜 실행, 파일의 접근만을 허용한다.
보호된 영역에서 애플리케이션의 기능이 수행되기 때문에 외부의 공격을 최소화할 수 있는 효과를 가진다.
각 애플리케이션은 실행 목적과 기능이 천차만별이기 때문에 샌드박스는 애플리케이션 개발자가 직접 명시해야 한다.
샌드박스를 적용 시에 애플리케이션에 대한 기능과 보안 관련 지식이 부족하면 서비스의 접근성을 과하게 해치며 일부 기능이 정상적으로 실행되지 않거나 우회될 수 있기 때문에 정확한 이해가 뒷받침되어야 한다.
SECCOMP
SECure COMPuting mode (SECCOMP) : 리눅스 커널에서 프로그램의 샌드박싱 매커니즘을 제공하는 컴퓨터 보안 기능
SECCOMP를 사용하면 애플리케이션에서 불필요한 시스템 콜의 호출을 방지할 수 있다.
애플리케이션에서 외부의 시스템 명령어를 실행하지 않는다면, execve와 같은 시스템 콜이 굳이 실행될 필요가 없다.
해당 시스템 콜은 공격 시에 일반적으로 임의의 명령어를 실행하기 위해 사용된다.
예를 들어, execve 시스템 콜의 실행을 방지하는 정책을 적용하면 외부의 공격으로부터 execve 시스템 콜이 실행될 경우 애플리케이션을 즉시 종료하게 되어 애플리케이션의 취약점이 존재해도 외부의 공격으로부터 피해를 최소화할 수 있다.
SECCOMP는 두 가지의 모드를 선택해서 적용할 수 있다.
아래는 해당 기능의 일부 코드이며, 아래에서 각 모드에 대한 설명을 확인할 수 있다.
int __secure_computing(const struct seccomp_data *sd) {
int mode = current->seccomp.mode;
int this_syscall;
...
this_syscall = sd ? sd->nr : syscall_get_nr(current, task_pt_regs(current));
switch (mode) {
case SECCOMP_MODE_STRICT:
__secure_computing_strict(this_syscall); /* may call do_exit */
return 0;
case SECCOMP_MODE_FILTER:
return __seccomp_filter(this_syscall, sd, false);
...
}
}
STRICT_MODE
해당 모드는 read, write, exit, sigreturn 시스템 콜의 호출만을 허용하여 이외의 시스템 콜의 호출 요청이 들어오면 SIGKILL 시그널을 발생하고 프로그램을 종료한다.
FILTER_MODE
해당 모드는 원하는 시스템 콜의 호출을 허용하거나 거부할 수 있다.
적용하는 방법은 라이브러리 함수를 이용한 방법과 필터링에 주로 쓰이는 Berkeley Packet Filter (BPF) 문법을 통해 적용하는 방법 두 가지로 나뉜다.
SECCOMP 설치 명령어는 다음과 같다.
apt install libseccomp-dev libseccomp2 seccomp
STRICT_MODE
STRICT_MODE는 read, write, exit, sigreturn 시스템 콜의 호출만을 허용하여 이외의 시스템 콜의 호출 요청이 들어오면 SIGKILL 시그널을 발생하고 프로그램을 종료한다.
해당 모드는 매우 적은 시스템 콜만을 허용해 다양한 기능을 수행하는 애플리케이션에서 적용할 수 없다.
아래는 STRICT_MODE를 적용한 예제 코드이다.
// Name: strict_mode.c
// Compile: gcc -o strict_mode strict_mode.c
#include <fcntl.h>
#include <linux/seccomp.h>
#include <sys/prctl.h>
#include <unistd.h>
void init_filter() { prctl(PR_SET_SECCOMP, SECCOMP_MODE_STRICT); }
int main() {
char buf[256];
int fd = 0;
init_filter();
write(1, "OPEN!\n", 6);
fd = open("/bin/sh", O_RDONLY);
write(1, "READ!\n", 6);
read(fd, buf, sizeof(buf) - 1);
write(1, buf, sizeof(buf));
return 0;
}
코드를 살펴보면, init_filter 함수에서 prctl 함수를 사용해 해당 모드를 적용한 것을 볼 수 있다.
다음은 예제 코드의 실행 결과로, open 함수가 실행되지 않고 프로그램이 종료된 것을 확인할 수 있다.

STRICT_MODE 동작 원리
STRICT_MODE를 처리하는 코드를 살펴보면서 어떻게 read, write, exit, sigreturn 시스템 콜의 호출만을 허용하는지 알아보았다.
아래는 STRICT_MODE를 적용했을 때 실행되는 코드의 일부이다.
static const int mode1_syscalls[] = {
__NR_seccomp_read,
__NR_seccomp_write,
__NR_seccomp_exit,
__NR_seccomp_sigreturn,
-1, /* negative terminated */
};
#ifdef CONFIG_COMPAT
static int mode1_syscalls_32[] = {
__NR_seccomp_read_32,
__NR_seccomp_write_32,
__NR_seccomp_exit_32,
__NR_seccomp_sigreturn_32,
0, /* null terminated */
};
#endif
static void __secure_computing_strict(int this_syscall) {
const int *allowed_syscalls = mode1_syscalls;
#ifdef CONFIG_COMPAT
if (in_compat_syscall()) allowed_syscalls = get_compat_mode1_syscalls();
#endif
do {
if (*allowed_syscalls == this_syscall) return;
} while (*++allowed_syscalls != -1);
#ifdef SECCOMP_DEBUG
dump_stack();
#endif
seccomp_log(this_syscall, SIGKILL, SECCOMP_RET_KILL_THREAD, true);
do_exit(SIGKILL);
}
model_syscalls는 read, write, exit, sigreturn 시스템 콜의 번호를 저장하고 있는 변수이며, 애플리케이션의 호환 모드에 따라서 각 비트에 맞는 시스템 콜 번호를 저장한다.
이후 애플리케이션에서 시스템 콜이 호출되면 __secure_computing 함수에 먼저 진입한다.
해당 함수는 전달된 시스템 콜 번호가 model_syscalls 또는 model_syscalls_32에 미리 정의된 번호와 일치하는지 검사하고, 일치하지 않는다면 SIGKILL 시그널을 전달하고 SECCOMP_RET_KILL을 반환한다.
FILTER_MODE: 라이브러리 함수
FILTER_MODE는 원하는 시스템 콜의 호출을 허용하거나 거부할 수 있다.
해당 모드는 애플리케이션 기능에 맞춰 유연하게 시스템 콜 실행을 허용 및 거부할 수 있는 장점이 있다.
다음은 SECCOMP에서 제공하는 함수를 정리한 표이다.
함수 | 설명 |
seccomp_init | SECCOMP 모드의 기본 값을 설정하는 함수입니다. 임의의 시스템 콜이 호출되면 이에 해당하는 이벤트가 발생합니다. |
seccomp_rule_add | SECCOMP의 규칙을 추가합니다. 임의의 시스템 콜을 허용하거나 거부할 수 있습니다. |
seccomp_load | 앞서 적용한 규칙을 애플리케이션에 반영합니다. |
ALLOW LIST
seccomp 라이브러리 함수를 사용해 지정한 시스템 콜의 호출만을 허용하는 예제 코드이다
// Name: libseccomp_alist.c
// Compile: gcc -o libseccomp_alist libseccomp_alist.c -lseccomp
#include <fcntl.h>
#include <seccomp.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/prctl.h>
#include <unistd.h>
void sandbox() {
scmp_filter_ctx ctx;
ctx = seccomp_init(SCMP_ACT_KILL);
if (ctx == NULL) {
printf("seccomp error\n");
exit(0);
}
seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(rt_sigreturn), 0);
seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(exit), 0);
seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(exit_group), 0);
seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(read), 0);
seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(write), 0);
seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(open), 0);
seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(openat), 0);
seccomp_load(ctx);
}
int banned() { fork(); }
int main(int argc, char *argv[]) {
char buf[256];
int fd;
memset(buf, 0, sizeof(buf));
sandbox();
if (argc < 2) {
banned();
}
fd = open("/bin/sh", O_RDONLY);
read(fd, buf, sizeof(buf) - 1);
write(1, buf, sizeof(buf));
}
이대로 실행하면 에러가 뜬다.

해결방법 : sudo apt install libseccomp-dev 설치하기
https://github.com/zardus/preeny/issues/56
Seccomp dependency not listed in README · Issue #56 · zardus/preeny
Trying to compile on a fresh system results in: deexec.c:9:10: fatal error: seccomp.h: No such file or directory #include <seccomp.h> ^~~~~~~~~~~ compilation terminated. Which is fixed by (on...
github.com
암튼 해결했으니 다시 돌아가서...
코드의 sandbox 함수를 살펴보면, SCMP_ACT_KILL을 통해 모든 시스템 콜의 호출을 허용하지 않는 규칙을 생성한다.
생성된 규칙에 seccomp_rule_add 함수를 통해 세 번째 인자로 전달된 시스템 콜의 호출을 허용하는 코드를 명시하고, 해당 규칙을 정한다.
main 함수를 살펴보면, 앞서 만든 규칙을 적용하고 나서 프로그램 실행 시에 전달되는 인자 갯수에 따라 fork 함수의 호출을 결정한다.
fork 함수가 호출되면 적용한 규칙에 따라 함수의 호출의 호출을 허용하지 않는다.
인자를 전달하고 프로그램을 실행하면 “/bin/sh” 파일을 읽고 화면에 출력하지만, 인자를 전달하지 않을 경우 fork 함수가 호출되어 곧바로 프로그램이 종료된다.
다음은 예제 코드를 컴파일하고 실행한 결과이다.

뭔가... 훨씬 많이 깨져서 나온다... 나중에 컴퓨터 인코딩 언어를 확인해봐도 좋을 것 같다...
DENY LIST
아래는 seccomp 라이브러리 함수를 사용해 지정한 시스템 콜을 호출하지 못하도록 하는 예제 코드이다.
// Name: libseccomp_dlist.c
// Compile: gcc -o libseccomp_dlist libseccomp_dlist.c -lseccomp
#include <fcntl.h>
#include <seccomp.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/prctl.h>
#include <unistd.h>
void sandbox() {
scmp_filter_ctx ctx;
ctx = seccomp_init(SCMP_ACT_ALLOW);
if (ctx == NULL) {
exit(0);
}
seccomp_rule_add(ctx, SCMP_ACT_KILL, SCMP_SYS(open), 0);
seccomp_rule_add(ctx, SCMP_ACT_KILL, SCMP_SYS(openat), 0);
seccomp_load(ctx);
}
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));
}
코드의 sandbox 함수를 살펴보면, SCMP_ACT_ALLOW를 통해 모든 시스템 콜의 호출을 허용하는 규칙을 생성한다.
이렇게 생성된 규칙에 seccomp_rule_add 함수를 통해 세 번째 인자로 전달된 시스템 콜의 호출을 거부하는 규칙을 생성한다.
main 함수를 살펴보면, 앞서 만든 규칙을 적용하고나서 “/bin/sh” 파일을 읽고 화면에 출력하는 기능을 수행한다.
그러나 규칙을 살펴보면, 파일을 열기 위해 필요한 함수인 open과 openat 시스템 콜의 호출을 거부하는 것을 확인할 수 있다.
만약 open 또는 openat 시스템 콜이 호출되면 곧바로 프로그램이 종료될 것이다.
다음은 예제 코드를 컴파일하고 실행한 결과이다.

FILTER_MODE: BPF
Berkeley Packet Filter (BPF) : 커널에서 지원하는 Virtual Machine (VM)
본래에는 네트워크 패킷을 분석하고 필터링하는 목적으로 사용했다.
임의 데이터를 비교하고, 결과에 따라 특정 구문으로 분기하는 명령어를 제공한다.
라이브러리 함수를 통해 규칙을 정의한 것과 같이 특정 시스템 콜 호출 시에 어떻게 처리할지 명령어를 통해 구현할 수 있다.
BPF는 VM인만큼 다양한 명령어와 타입이 존재한다.
명령어 | 설명 |
BPF_LD | 인자로 전달된 값을 누산기에 복사합니다. 이를 통해 값을 복사한 후 비교 구문에서 해당 값을 비교할 수 있습니다. |
BPF_JMP | 지정한 위치로 분기합니다. |
BPF_JEQ | 설정한 비교 구문이 일치할 경우 지정한 위치로 분기합니다. |
BPF_RET | 인자로 전달된 값을 반환합니다. |
BPF Macro
BPF 코드를 직접 입력하지 않고 편리하게 원하는 코드를 실행할 수 있게끔 매크로를 제공한다.
BPF_STMT
operand에 해당하는 값을 명시한 opcode로 값을 가져온다.
opcode는 인자로 전달된 값에서 몇 번째 인덱스에서 몇 바이트를 가져올 것인지를 지정할 수 있다.
BPF_STMT(opcode, operand)
BPF_JUMP
BPF_STMT 매크로를 통해 저장한 값과 operand를 opcode에 정의한 코드로 비교하고, 비교 결과에 따라 특정 오프셋으로 분기한다.
BPF_JUMP(opcode, operand, true_offset, false_offset)
ALLOW LIST
다음은 BPF를 통해 지정한 시스템 콜의 호출만을 허용하는 예제 코드이다.
코드의 sandbox 함수를 살펴보면, filter 구조체에 BPF 코드가 작성되어 있는 것을 확인할 수 있다.
// Name: secbpf_alist.c
// Compile: gcc -o secbpf_alist secbpf_alist.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 ALLOW_SYSCALL(name) \
BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, __NR_##name, 0, 1), \
BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_ALLOW)
#define KILL_PROCESS BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_KILL)
#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, 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. */
ALLOW_SYSCALL(rt_sigreturn),
ALLOW_SYSCALL(open),
ALLOW_SYSCALL(openat),
ALLOW_SYSCALL(read),
ALLOW_SYSCALL(write),
ALLOW_SYSCALL(exit_group),
KILL_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;
}
void banned() { fork(); }
int main(int argc, char* argv[]) {
char buf[256];
int fd;
memset(buf, 0, sizeof(buf));
sandbox();
if (argc < 2) {
banned();
}
fd = open("/bin/sh", O_RDONLY);
read(fd, buf, sizeof(buf) - 1);
write(1, buf, sizeof(buf));
return 0;
}
이번 코드에 #include <string.h>를 추가해야 실행된다.
아키텍처 검사
현재 아키텍처가 X86_64라면 다음 코드로 분기하고, 다른 아키텍처라면 SECCOMP_RET_KILL을 반환하고 프로그램을 종료한다.
#define arch_nr (offsetof(struct seccomp_data, arch))
#define ARCH_NR AUDIT_ARCH_X86_64
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),
시스템 콜 검사
호출된 시스템 콜의 번호를 저장하고, ALLOW_SYSCALL 매크로를 호출한다.
해당 매크로는 호출된 시스템 콜이 인자로 전달된 시스템 콜과 일치하는지 비교하고 같다면 SECCOMP_RET_ALLOW를 반환한다.
만약 다른 시스템 콜이라면 KILL_PROCESS를 호출해 SECCOMP_RET_KILL을 반환하고 프로그램을 종료한다.
#define ALLOW_SYSCALL(name) \
BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, __NR_##name, 0, 1), \
BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_ALLOW
#define KILL_PROCESS \
BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_KILL)
BPF_STMT(BPF_LD+BPF_W+BPF_ABS, syscall_nr),
ALLOW_SYSCALL(rt_sigreturn),
ALLOW_SYSCALL(open),
ALLOW_SYSCALL(openat),
ALLOW_SYSCALL(read),
ALLOW_SYSCALL(write),
ALLOW_SYSCALL(exit_group),
KILL_PROCESS,
코드의 실행 결과는 다음과 같다.

DENY LIST
다음은 BPF를 통해 지정한 시스템 콜을 호출하지 못하도록 하는 예제 코드이다.
코드의 sandbox 함수를 살펴보면, filter 구조체에 BPF 코드가 작성되어 있는 것을 확인할 수 있다.
// 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_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, 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;
}
아까와 같이 <string.h> 헤더 파일을 추가해줘야 한다.
아키텍처 검사
현재 아키텍처가 X86_64라면 다음 코드로 분기하고, 다른 아키텍처라면 SECCOMP_RET_KILL을 반환하고 프로그램을 종료한다.
#define arch_nr (offsetof(struct seccomp_data, arch))
#define ARCH_NR AUDIT_ARCH_X86_64
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),
시스템 콜 검사
호출된 시스템 콜의 번호를 저장하고, DENY_SYSCALL 매크로를 호출한다.
해당 매크로는 호출된 시스템 콜이 인자로 전달된 시스템 콜과 일치하는지 비교하고 같다면 SECCOMP_RET_KILL을 반환해 프로그램을 종료한다.
#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)
BPF_STMT(BPF_LD+BPF_W+BPF_ABS, syscall_nr),
DENY_SYSCALL(open),
DENY_SYSCALL(openat),
MAINTAIN_PROCESS,
실행 결과는 다음과 같다.

seccomp-tools
SECCOMP 규칙이 복잡할 경우 바이너리 분석에 있어 어려움을 느낄 수 있다.
C 코드로 작성된 BPF 문법은 직관적이기 때문에 이해하는데에 오랜 시간이 걸리지 않지만, 컴파일 된 이후 바이너리를 분석할 때에는 일일히 바이트 코드를 변환해야 하기 때문에 어려움을 느낄 수 있다.
seccomp-tools는 SECCOMP가 적용된 바이너리의 분석을 도울 뿐만 아니라 BPF 어셈블러/디스어셈블러를 제공하는 유용한 도구이다.
이를 설치하기 위한 명령어와 설치된 모습은 다음과 같다.
$ sudo apt install gcc ruby-dev
$ gem install seccomp-tools

권한이 없으면 권한을 주면 된다...ㅎㅎ

잘 설치되었다.
해당 도구에 대한 자세한 내용 및 사용법은 아래 링크에서 확인할 수 있다.
https://github.com/david942j/seccomp-tools
GitHub - david942j/seccomp-tools: Provide powerful tools for seccomp analysis
Provide powerful tools for seccomp analysis. Contribute to david942j/seccomp-tools development by creating an account on GitHub.
github.com
마치며
- 샌드박스(Sandbox): 외부의 공격으로부터 시스템을 보호하기 위해 설계된 기법
- SECure COMPuting mode (SECCOMP): 리눅스 커널에서 프로그램의 샌드박싱 매커니즘을 제공하는 컴퓨터 보안 기능
- Berkeley Packet Filter (BPF): BPF는 커널에서 지원하는 Virtual Machine (VM)으로, 본래에는 네트워크 패킷을 분석하고 필터링하는 목적으로 사용됨
Quiz: SECCOMP
A Jump Mode
B Siege Mode
C Strict Mode
D Allow Mode
Q2. 다음 코드는 두 가지의 SECCOMP 리스트 중 어떤 리스트인가요?
seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(rt_sigreturn), 0);
seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(exit), 0);
seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(exit_group), 0);
seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(read), 0);
seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(write), 0);
seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(open), 0);
seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(openat), 0);
A DENY LIST
B ALLOW LIST
Q3. BPF와 연관없는 항목은?
A BPF_PULL
B BPF_JMP
C BPF_JUMP
D BPF_STMT
Q4. 지문 설명에 해당하는 모드는 무엇인가요?
read, write, exit, sigreturn 시스템 콜의 호출만을 허용한다.
A Sicko Mode
B Siege Mode
C Strict Mode
D Filter Mode